我想通过命令行在HTML文件上运行查找和替换。
我的命令看起来像这样:
1
| sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html |
当我运行它并在之后查看该文件时,它是空的。 它删除了我的文件的内容。
当我再次恢复文件后运行它:
1
| sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html |
stdout是文件的内容,已执行查找和替换。
为什么会这样?
-
Perl替代方案:perl -pi -w -e 's/STRING_TO_REPLACE/REPLACE_WITH/g;' index.html
-
很多相关的sed命令,用于查找字符串并替换整行:stackoverflow.com/questions/11245144/
-
看看这个:如何在同一个管道中读取和写入同一个文件总是"失败"? 在Unix和Linux上。
当shell在命令行中看到> index.html时,它会打开文件index.html进行写入,擦除其以前的所有内容。
要解决此问题,您需要将-i选项传递给sed以进行内联更改并在原始文件执行更改之前创建原始文件的备份:
1
| sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html |
如果没有.bak,命令将在某些平台上失败,例如Mac OSX。
-
说truncates the file而不是opens the file可能会让它更清晰。
-
至少在我的Mac上,第一个建议不起作用......如果你在文件上进行就地替换,你必须指定一个扩展名。你至少可以传入一个零长度的扩展名:sed -i's / STRING_TO_REPLACE / STRING_TO_REPLACE_IT / g index.html
-
对于变量sed -i.bak的''$ search'/'$ replace'/ g'index.html
-
谢谢。在Mac OSX中没有找到备份扩展名必须提到的地方。当我使用名为foo的文件尝试它而没有提供任何扩展时,抛出invalid character code f错误。
-
在osx上,使用空字符串''作为-i的参数,如:sed -i '' 's/blah/xx/g'
-
但sed -i之后你的.bak是什么?
-
在Win7 64上使用cygwin我得到了临时文件和原始文件都没了,没有替换。
-
@smallduck感谢您的评论。我讨厌它在mac上创建一个新的bak文件。你的答案解决了我的问题。
-
对于Mac用户:您还可以安装gnu-sed而不是Mac上使用的BSD版本。见这里:apple.stackexchange.com/a/195595
-
通过python的哲学,"显式优于隐式",这里的命令完全相同但更具可读性:sed --in-place".bak" s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html
-
只是为了进一步澄清。如果它已经sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index_new.html那就可以了。混乱源于我们从左到右阅读的事实。但是会发生这样的情况:首先截断文件以准备随后的sed命令,该命令最终在已经空的文件上运行。
另一种有用的模式是:
1
| sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html |
这有很多相同的效果,不使用-i选项,另外意味着,如果sed脚本由于某种原因失败,输入文件不会被破坏。此外,如果编辑成功,则没有剩余的备份文件。这种习惯用法在Makefile中很有用。
相当多的seds都有-i选项,但不是全部; posix sed是一个没有的。因此,如果您的目标是可移植性,那么最好避免使用。
-
+1用于考虑可移植性
-
没有备份文件的+1,如果编辑失败,则不会破坏输入文件。在mac上完美地工作。
-
只有在Win7 64 Cygwin上为我工作的解决方案
-
完美地为我工作。谢谢! (在Mac上)
-
这对我很有用,在Ubuntu Server 14.04 sed -i保持归零文件。
-
非常小的增强:... && mv index.html{.tmp,}
-
@EdwardGarson的确,这可能是我在输入时使用的 - 我同意它更整洁 - 但是sh(如果我没记错的话)没有那个{...}扩展。在Makefile中,您可能正在使用sh而不是bash,因此如果您的目标是可移植性(或后缀),那么您将需要避免这种构造。
-
很好地指出@NormanGray。
-
或更短:mv index.html $(echo index.html | sed -e 'script')
1
| sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html |
这会对文件index.html进行全局就地替换。引用字符串可以防止查询和替换中的空格问题。
使用sed的-i选项,例如
1
| sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html |
-
适用于我。接受的答案没有
-
这是什么意思? sed:-i不能与stdin一起使用
-
如果模式包含空格 - 's/STRING_TO_REPLACE/REPLACE_WITH/g',请记住用引号括起您的模式
-
@sheetal:-i执行文件的就地编辑,因此将它与stdin输入结合起来没有意义。
-
这可能适用于macOS,但它不适用于Arch Linux。
要更改多个文件(并将每个文件的备份保存为* .bak):
1
| perl -p -i -e"s/\|/x/g" * |
将获取目录中的所有文件,并将|替换为x
这被称为"Perl馅饼"(简单的馅饼)
-
很高兴看到有人愿意查看问题陈述,而不仅仅是标签。 OP未指定sed作为要求,仅将其用作已尝试过的工具。
您应该尝试使用选项-i进行就地编辑。
1
| sed -i.bak"s#https.*\.com#$pub_url#g" MyHTMLFile.html |
如果您要添加链接,请尝试此操作。按上述方式搜索URL(以https开头,此处以..com结尾)并将其替换为URL字符串。我在这里使用了变量$pub_url。 s此处表示搜索,g表示全局替换。
有用 !
警告:这是一种危险的方法!它滥用了linux中的i / o缓冲区,并且具有缓冲的特定选项,它可以处理小文件。这是一个有趣的好奇心。但是不要将它用于真实的情况!
除了sed的-i选项
您可以使用tee实用程序。
来自man:
tee - read from standard input and write to standard output and files
所以,解决方案是:
1
| sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html |
- 这里重复tee以确保管道被缓冲。然后阻塞管道中的所有命令,直到它们获得一些输入为止。当上游命令将1个字节缓冲区(大小在某处定义)写入命令的输入时,管道中的每个命令都会启动。因此,最后一个命令tee index.html打开文件进行写入并因此将其清空,在上游管道完成并且输出位于管道内的缓冲区之后运行。
最有可能以下情况不起作用:
1
| sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee index.html |
- 它将同时运行管道的两个命令而不会阻塞。 (不阻塞管道应该逐行传递字节而不是缓冲区缓冲区。与运行cat | sed s/bar/GGG/时相同。没有阻塞它更具交互性,通常只有2条命令的管道在没有缓冲和阻塞的情况下运行。更长的管道被缓冲。 )tee index.html将打开文件进行写入,它将被清空。但是,如果您始终打开缓冲,第二个版本也会起作用。
-
tee的输出文件也立即打开,导致整个命令的空index.html。
-
这将破坏任何大于管道缓冲区的输入文件(通常为64KB)。 (@sjngm:该文件不会像>那样立即被截断,但重点是它是一个破碎的解决方案,很可能导致数据丢失)。
命令的问题
是的,在sed实际处理它之前,shell会截断file。结果,您得到一个空文件。
执行此操作的sed方法是使用-i进行编辑,如其他答案所示。但是,这并不总是你想要的。 -i将创建一个临时文件,然后用于替换原始文件。如果您的原始文件是链接(链接将被常规文件替换),则会出现问题。如果需要保留链接,可以使用临时变量存储sed的输出,然后再将其写回文件,如下所示:
1
| tmp=$(sed 'code' file); echo -n"$tmp"> file |
更好的是,使用printf而不是echo,因为echo可能会在某些shell(例如破折号)中将\\处理为\:
1
| tmp=$(sed 'code' file); printf"%s""$tmp"> file |
-
+1用于保留链接。 它也适用于临时文件:sed 'code' file > file.tmp; cat file.tmp > file; rm file.tmp
ed回答:
1 2
| printf"%s
" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html |
为了重申codaddict的回答,shell首先处理重定向,擦除"input.html"文件,然后shell调用"sed"命令将其传递给现在为空的文件。
-
快速提问,为什么人们不断给出sed答案的"ed版本"?它表现得更快吗?
-
某些sed未实现-i进行就地编辑。 ed无处不在,可以让您将编辑内容保存到原始文件中。另外,套件中有很多工具总是很好。
-
好的。所以,表现明智,我认为它们是一样的。谢谢!
您可以在Ex模式下使用Vim:
1
| ex -sc '%s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g|x' index.html |
%选择所有行
x保存并关闭
在充分尊重上述正确答案的情况下,这样的"干运行"脚本总是一个好主意,这样您就不会破坏文件并且必须从头开始。
只需让你的脚本将输出溢出到命令行而不是将其写入文件,例如,像这样:
1
| sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html |
要么
1
| less index.html | sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g |
这样,您可以查看并检查命令的输出,而不会截断文件。
我正在寻找可以定义行范围并找到答案的选项。例如,我想从第36-57行将host1更改为host2。
1
| sed '36,57 s/host1/host2/g' myfile.txt > myfile1.txt |
您也可以使用gi选项忽略字符大小写。
1
| sed '30,40 s/version/story/gi' myfile.txt > myfile1.txt |