624

我想通过命令行在 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内容,并且已经执行了查找和替换。

为什么会这样?

4

12 回答 12

961

shell在命令行中看到 > index.html它时,它会打开index.html写入的文件,擦除之前的所有内容。

要解决此问题,您需要传递-i选项以sed进行内联更改并在原地进行更改之前创建原始文件的备份:

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

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

于 2011-03-02T18:48:27.940 回答
216

另一种有用的模式是:

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

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

很多 seds 都有-i选择,但不是全部;posix sed 不是。因此,如果您的目标是便携性,则最好避免。

于 2011-03-02T22:32:48.537 回答
96
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html

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

于 2013-08-09T20:58:10.580 回答
59

使用 sed 的 -i 选项,例如

sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html
于 2011-03-02T18:48:40.530 回答
18

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

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

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

于 2013-06-20T20:54:08.733 回答
14

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

于 2011-03-02T18:49:13.917 回答
7

警告:这是一种危险的方法!它滥用 linux 中的 i/o 缓冲区,并通过特定的缓冲选项设法处理小文件。这是一个有趣的好奇心。但不要将其用于实际情况!

除了 您可以使用该实用程序-i的选项。sedtee

来自man

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意志打开文件进行写入,它将被清空。但是,如果您始终打开缓冲,则第二个版本也可以使用。

于 2013-07-16T22:06:23.483 回答
6
sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html

如果您有要添加的链接,请尝试此操作。搜索上述 URL(此处以 https 开头,以 .com 结尾)并将其替换为 URL 字符串。我在$pub_url这里使用了一个变量。s这里的意思是搜索,g意思是全局替换。

有用 !

于 2015-10-09T06:24:26.870 回答
4

命令的问题

sed 'code' file > file

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

正如其他答案所建议的那样,执行此操作的 sed 方法是用于-i就地编辑。但是,这并不总是您想要的。-i将创建一个临时文件,然后用于替换原始文件。如果您的原始文件是一个链接(该链接将被常规文件替换),这将是有问题的。如果需要保留链接,可以使用临时变量来存储 sed 的输出,然后再将其写回文件,如下所示:

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

更好的是,使用printf而不是echo因为echo可能会\\\在某些外壳中那样处理(例如破折号):

tmp=$(sed 'code' file); printf "%s" "$tmp" > file
于 2015-07-29T22:21:11.097 回答
3

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”命令,将其传递给一个现在为空的文件。

于 2011-06-28T01:07:54.780 回答
0

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

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

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

sed '30,40 s/version/story/gi' myfile.txt > myfile1.txt
于 2017-08-11T07:05:05.107 回答
-1

在充分尊重上述正确答案的情况下,像这样“试运行”脚本总是一个好主意,这样您就不会损坏文件并且必须从头开始重新开始。

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

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 

这样您就可以查看和检查命令的输出,而不会截断您的文件。

于 2017-08-25T12:47:27.030 回答