如何编写一个' sed '脚本,将两个标记之间的文本替换为另一个文件的内容



我想写一个sed脚本,用另一个文件的内容替换两个标记之间的文本。

假设我有以下文件,标记为<!-- Start --><!-- End -->:

# index.html
...
<!-- Start -->
<p>Old content</p>
<!-- End -->
...

我想用这个文件的内容替换里面的文本:

# snippet.html
<p>New content</p>

我试了这个sed脚本:

$ cat snippet.html | sed -i -e '/<!-- Start -->/,/<!-- End -->/ { r /dev/stdin' -e';d};' index.html

它替换了内容和标记,但我需要保留<!-- Start --><!-- End -->标记这样我就可以在将来再次替换内容。

我应该对sed脚本做什么更改?

提前感谢!

你所需要做的就是在d之前添加//!:

cat snippet | sed -e '/<!-- Start -->/,/<!-- End -->/ { r /dev/stdin' -e '; //!d }' file

//是"last match"…所以在{ }中没有任何其他匹配的/START/,/END/{ }的情况下,它将匹配/START//END/

//!d确保除开头和结尾匹配的行外,其他范围将被删除。

ETA:正如@potong在评论中提到的,r /dev/stdin的使用似乎是一个特殊情况——只有第一个r会向输出流添加任何内容。

这可能适合您(GNU sed):

sed -e '/<!-- Start -->/{n;r snippetFile' -e ':a;N;/<!-- End -->/D;s/n//;ba}' file 

打印开始标记,然后追加代码段文件。

收集行直到结束标记,删除它们的换行并使用D命令删除它们,保留结束标记。

注意:解决方案分为两部分,因为r命令需要换行符作为结束符(单独的命令集具有与换行符相同的效果)。

上述解决方案不适合必须插入假行的空标记:

sed -e '/<!-- Start -->/{n;r snippetFile ' -e 's/^/n/;:a;N;/<!-- End -->/D;s/n//g;ba}' file

另一种解决方案是在代码片段文件中插入并追加标记:

sed -z 's/^/<!-- Start -->n/;s/.*/&\/mg;s/$/<!-- End -->/' snippetFile |
sed '/<!-- Start -->/,/<!-- End -->/c'"$(cat)" file

注意:在此解决方案中,c命令期望除最后一行外的所有行都以结束。

假设标记单独在其行上:

cat snippet.html | sed -i -n -e '
/<!-- Start -->/r /dev/stdin
1,//{;p;d;}
/<!-- End -->/,$p
' index.html
  • //重复前面的正则表达式搜索

如果第一个标记在文件的第一行,则上面的代码失败。在这种情况下,使用GNU sed可以使用0,//代替1,//。或者,这个版本应该可以正常工作:

cat snippet.html | sed -i -n -e '
/<!-- $Start -->/{
p
r /dev/stdin
:d
n
/<!-- End -->/!bd
}
p
' index.html

最新更新