我需要替换按ID排序的模式范围的每行的开头,我使用sed,但欢迎其他语言!
这是带有目标的示例文本
...
==OPEN==
data: blabla
id: class1
moredata: blabla
==CLOSE==
==OPEN==
id: class2
boringdata: blabla
==CLOSE==
...extra info
==OPEN==
id: class8
data: ...
==CLOSE==
...more info
==OPEN==
data: ...
boringdata: ...
id: class10
==CLOSE==
...
如果我注释掉id为8的模式,预期的输出将是:
...
==OPEN==
data: blabla
id: class1
moredata: blabla
==CLOSE==
==OPEN==
id: class2
boringdata: blabla
==CLOSE==
...extra info
// ==OPEN==
// id: class8
// data: ...
// ==CLOSE==
...more info
==OPEN==
data: ...
boringdata: ...
id: class10
==CLOSE==
...
我得到的最接近的代码是这样的,但我必须重写整个范围,这是负担不起的:
sed -e '/==OPEN==/{:loop;N;/= = = =/!b循环;/id: class8/{s/。*/需要重写/}}'/example
如果我告诉它重写开头(^),它只重写范围的第一行,我认为这是因为它认为整个模式为一行。
我得到的最接近的代码是这个,但是我必须重写整个范围和价格都不合理:
sed -e '/==OPEN==/{:loop;N;/= = = =/!b循环;/id: class8/{s/。*/需要重写/}}'/example
还不错。
如果我告诉它重写开头(^),它只重写第一个线的范围,我想是因为它考虑了整个模式为一行
是的,POSIXsed
和GNUsed
默认情况下,^
只匹配模式空间的开头。但是,您可以匹配换行符本身:
sed -e '/==OPEN==/ {:loop; N; /==CLOSE==/! b loop; /id: class8/ {s,(^|n),1// ,g}}'
/example
特别注意:
- 被替换的文本表示为组
(^|n)
,表示模式空间开头的零长度子字符串或换行符,将其作为组捕获。 - 匹配的文本通过
1
回显到替换中。当^
替代匹配时,这没有明显的影响,但它避免了在其他替代匹配时消除换行符。 - 逗号(
,
)用作模式分隔符,因此替换文本中的斜杠(/
)不需要转义。
g
标志用于使模式的所有外观被替换,而不仅仅是第一个。如果你愿意依赖GNU扩展,那么你可以做得更简单一点:
sed -e '/==OPEN==/ {:loop; N; /==CLOSE==/! b loop; /id: class8/ {s,^,// ,gm}}'
/example
对于GNUsed
,s
命令中的m
标志使^
在模式空间的开始和每个换行符之后匹配。这个标志不是POSIX指定的。