Find and replace in file and overwrite file行不通,它会清空文件

我想通过命令行在HTML文件上运行查找和替换。

我的命令看起来像这样:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html

当我运行它并在之后查看该文件时,它是空的。它删除了我文件的内容。

当我再次恢复文件后运行这个:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

stdout是文件的内容,并且已经执行了查找和替换。

为什么会这样?

744046 次浏览

壳牌在命令行中看到> index.html时,它会为写作打开文件index.html,删除之前的所有内容。

要解决这个问题,你需要将-i选项传递给sed来进行内联更改,并在原始文件进行更改之前创建一个备份:

sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

如果没有.bak,该命令将在某些平台上失败,例如Mac OSX。

使用sed的-i选项,例如:

sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html

您应该尝试使用-i选项进行就地编辑。

另一种有用的模式是:

sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html

这与不使用-i选项具有大致相同的效果,并且还意味着,如果sed脚本由于某种原因失败,输入文件也不会被破坏。此外,如果编辑成功,就不会留下备份文件。这种习惯用法在makefile中很有用。

相当多的种子有-i选项,但不是所有的;posix sed则不是。因此,如果您的目标是可移植性,最好避免使用这种方法。

ed的答案是:

printf "%s\n" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html

为了重申codaddict回答, shell处理重定向第一个,清除“input.html”文件,而然后, shell调用“sed”命令传递给它一个现在为空的文件。

要更改多个文件(并将每个文件的备份保存为*.bak):

perl -p -i -e "s/\|/x/g" *

将获取目录中的所有文件,并将|替换为x 这被称为“Perl饼”(简单如饼)

它滥用了linux中的i/o缓冲区,通过特定的缓冲选项,它可以在小文件上工作。这是一件有趣的奇事。# EYZ1

除了sed-i选项 你可以使用# EYZ0效用.

从# EYZ0:

Tee -从标准输入读取并写入标准输出和文件

所以,解决方案是:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html

—这里重复使用tee以确保管道被缓冲。然后,管道中的所有命令都将被阻塞,直到它们获得一些可以处理的输入。当上游命令已经将1个字节缓冲区(大小定义为的某个地方)写入命令的输入时,管道中的每个命令就开始了。因此,最后一条命令tee index.html(它打开文件进行写入并因此清空它)在上游管道完成并且输出位于管道中的缓冲区之后运行。

下面的方法很可能行不通:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee index.html

——它会同时运行管道的两个命令,没有任何阻塞。(在不阻塞的情况下,管道应该逐行传递字节,而不是逐缓冲区传递。与运行cat | sed s/bar/GGG/时相同。没有阻塞,它更具交互性,通常只有2个命令的管道在没有缓冲和阻塞的情况下运行。较长的管道被缓冲。)tee index.html将打开文件进行写入,并将其清空。但是,如果始终打开缓冲,第二个版本也可以工作。

sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html

这将对文件index.html进行全局就地替换。引用字符串可以防止查询和替换中出现空白的问题。

命令的问题

sed 'code' file > file

file在sed实际处理它之前被shell截断。结果,您将得到一个空文件。

sed的方法是使用-i在适当的位置编辑,就像其他答案建议的那样。然而,这并不总是你想要的。-i将创建一个临时文件,然后用它来替换原始文件。如果您的原始文件是一个链接(该链接将被一个常规文件取代),这就有问题了。如果你需要保存链接,你可以使用一个临时变量来存储sed的输出,然后再把它写回文件,就像这样:

tmp=$(sed 'code' file); echo -n "$tmp" > file

更好的是,使用printf而不是echo,因为echo很可能在某些shell(例如dash)中将\\处理为\:

tmp=$(sed 'code' file); printf "%s" "$tmp" > file
sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html

如果你有一个链接要添加,试试这个。按照上面的方法搜索URL(这里以https开始,以。com结束),并将其替换为URL字符串。我在这里使用了一个变量$pub_urls表示搜索,g表示全局替换。

真的有用!

我正在寻找可以定义直线范围的选项,并找到了答案。例如,我想将host1从第36-57行更改为host2。

sed '36,57 s/host1/host2/g' myfile.txt > myfile1.txt

你也可以使用gi选项来忽略字符大小写。

sed '30,40 s/version/story/gi' myfile.txt > myfile1.txt

尽管对上面的正确答案表示尊重,但像那样“演练”脚本总是一个好主意,这样就不会破坏文件,而不得不从头开始。

让你的脚本将输出溢出到命令行,而不是写入文件,例如,像这样:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

less index.html | sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g

通过这种方式,您可以查看和检查命令的输出,而不会截断文件。