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

为什么会这样?


当前回答

警告:这是一个危险的方法!它滥用了linux中的i/o缓冲区,通过特定的缓冲选项,它可以处理小文件。这是一件有趣的奇事。但是不要在真实的情况下使用它!

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

从男人:

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

所以,解决方案是:

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

-- here the tee is repeated to make sure that the pipeline is buffered. Then all commands in the pipeline are blocked until they get some input to work on. Each command in the pipeline starts when the upstream commands have written 1 buffer of bytes (the size is defined somewhere) to the input of the command. So the last command tee index.html, which opens the file for writing and therefore empties it, runs after the upstream pipeline has finished and the output is in the buffer within the pipeline.

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

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

-- it will run both commands of the pipeline at the same time without any blocking. (Without blocking the pipeline should pass the bytes line by line instead of buffer by buffer. Same as when you run cat | sed s/bar/GGG/. Without blocking it's more interactive and usually pipelines of just 2 commands run without buffering and blocking. Longer pipelines are buffered.) The tee index.html will open the file for writing and it will be emptied. However, if you turn the buffering always on, the second version will work too.

其他回答

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

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

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

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

警告:这是一个危险的方法!它滥用了linux中的i/o缓冲区,通过特定的缓冲选项,它可以处理小文件。这是一件有趣的奇事。但是不要在真实的情况下使用它!

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

从男人:

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

所以,解决方案是:

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

-- here the tee is repeated to make sure that the pipeline is buffered. Then all commands in the pipeline are blocked until they get some input to work on. Each command in the pipeline starts when the upstream commands have written 1 buffer of bytes (the size is defined somewhere) to the input of the command. So the last command tee index.html, which opens the file for writing and therefore empties it, runs after the upstream pipeline has finished and the output is in the buffer within the pipeline.

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

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

-- it will run both commands of the pipeline at the same time without any blocking. (Without blocking the pipeline should pass the bytes line by line instead of buffer by buffer. Same as when you run cat | sed s/bar/GGG/. Without blocking it's more interactive and usually pipelines of just 2 commands run without buffering and blocking. Longer pipelines are buffered.) The tee index.html will open the file for writing and it will be emptied. However, if you turn the buffering always on, the second version will work too.

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

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

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

OR

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

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

命令的问题

sed 'code' 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

我正在寻找可以定义直线范围的选项,并找到了答案。例如,我想将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