Shell 在文件中查找和替换并覆盖文件';不行,它会清空文件

Shell 在文件中查找和替换并覆盖文件';不行,它会清空文件,shell,unix,sed,io-redirection,Shell,Unix,Sed,Io Redirection,我想通过命令行对HTML文件运行查找和替换 我的命令如下所示: sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html tmp=$(sed 'code' file); echo -n "$tmp" > file 当我运行这个程序,然后查看文件时,它是空的。它删除了我文件的内容 再次还原文件后运行此操作时: sed -e s/STRING_TO_REPLACE/STRING_TO_REPLA

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

我的命令如下所示:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html
tmp=$(sed 'code' file); echo -n "$tmp" > file
当我运行这个程序,然后查看文件时,它是空的。它删除了我文件的内容

再次还原文件后运行此操作时:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html
stdout
是文件的内容,已经执行了查找和替换


为什么会发生这种情况?

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

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

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

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

shell在命令行中看到
>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

使用sed的-i选项,例如

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

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

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

另一种有用的模式是:

sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html
这在不使用
-i
选项的情况下具有大致相同的效果,另外还意味着,如果sed脚本由于某种原因失败,输入文件不会被关闭。此外,如果编辑成功,则不会留下任何备份文件。这种习惯用法在makefile中很有用


相当多的SED都有
-i
选项,但不是所有SED都有;posix sed是一个没有。因此,如果您的目标是可移植性,最好避免使用。

另一种有用的模式是:

sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html
这在不使用
-i
选项的情况下具有大致相同的效果,另外还意味着,如果sed脚本由于某种原因失败,输入文件不会被关闭。此外,如果编辑成功,则不会留下任何备份文件。这种习惯用法在makefile中很有用


相当多的SED都有
-i
选项,但不是所有SED都有;posix sed是一个没有。因此,如果您的目标是可移植性,最好避免使用。

ed
答案:

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

为了重申这一点,shell首先处理重定向,清除“input.html”文件,然后调用“sed”命令传递一个现在为空的文件

ed
答案:

printf "%s\n" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html
为了重申这一点,shell首先处理重定向,清除“input.html”文件,然后调用“sed”命令传递一个现在为空的文件

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

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

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

将获取目录中的所有文件,并将
|
替换为
x

这被称为“Perl派”(非常简单)

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

除了
sed的
-i
选项之外 您可以使用
tee
实用程序

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/
时相同。在不阻塞的情况下,它更具交互性,通常只有两个命令的管道在不缓冲和阻塞的情况下运行。缓冲更长的管道。)
tee index.html
将打开文件进行写入,文件将被清空。但是,如果始终打开缓冲,第二个版本也会工作。

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

sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html
除了
sed的
-i
选项之外 您可以使用
tee
实用程序

man

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

因此,解决办法是:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html
--此处重复
tee
,以确保管道得到缓冲。然后,管道中的所有命令都会被阻塞,直到它们获得一些要处理的输入。管道中的每个命令在
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