我想写一个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