用 sed 逐行替换模式范围
Replace a pattern range line by line with sed
我需要替换按 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; /==CLOSE==/! b loop; /id: class8/ {s/.*/NEEDS REWRITE/}}' /example
如果我告诉它重写开头 (^),它只重写范围的第一行,我认为这是因为它把整个模式视为一行。
The closest code I have gotten is this, but I have to rewrite the
entire range and it is not affordable:
sed -e '/==OPEN==/ {:loop; N; /==CLOSE==/! b loop; /id: class8/ {s/.*/NEEDS REWRITE/}}' /example
其实还不错。
If I tell it to rewrite the beginning (^), it rewrites only the first
line of the range, I think it is because it considers the entire
pattern as one line.
是的,默认情况下 POSIX sed
和 GNU sed
,^
仅匹配模式 space 的开头。但是,您可以自己匹配换行符:
sed -e '/==OPEN==/ {:loop; N; /==CLOSE==/! b loop; /id: class8/ {s,\(^\|\n\),// ,g}}' \
/example
特别注意:
- 被替换的文本表示为组
\(^\|\n\)
,表示模式 space 开头的零长度子字符串或作为组捕获的换行符。
- 匹配的文本通过
</code> 回显到替换中。当匹配 <code>^
替代项时,这没有明显的效果,但它避免在其他替代项匹配时消除换行符。
- 逗号(
,
)用作模式分隔符,因此替换文本中的斜线(/
)不需要转义。
g
标志用于导致所有 次出现的模式被替换,而不仅仅是第一个。
如果你愿意依赖 GNU 扩展,那么你可以做的更简单一点:
sed -e '/==OPEN==/ {:loop; N; /==CLOSE==/! b loop; /id: class8/ {s,^,// ,gm}}' \
/example
使用 GNU sed
,s
命令中的 m
标志导致 ^
在模式 space 的开头和立即匹配在每个换行符之后。此标志未由 POSIX.
指定
我需要替换按 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; /==CLOSE==/! b loop; /id: class8/ {s/.*/NEEDS REWRITE/}}' /example
如果我告诉它重写开头 (^),它只重写范围的第一行,我认为这是因为它把整个模式视为一行。
The closest code I have gotten is this, but I have to rewrite the entire range and it is not affordable:
sed -e '/==OPEN==/ {:loop; N; /==CLOSE==/! b loop; /id: class8/ {s/.*/NEEDS REWRITE/}}' /example
其实还不错。
If I tell it to rewrite the beginning (^), it rewrites only the first line of the range, I think it is because it considers the entire pattern as one line.
是的,默认情况下 POSIX sed
和 GNU sed
,^
仅匹配模式 space 的开头。但是,您可以自己匹配换行符:
sed -e '/==OPEN==/ {:loop; N; /==CLOSE==/! b loop; /id: class8/ {s,\(^\|\n\),// ,g}}' \
/example
特别注意:
- 被替换的文本表示为组
\(^\|\n\)
,表示模式 space 开头的零长度子字符串或作为组捕获的换行符。 - 匹配的文本通过
</code> 回显到替换中。当匹配 <code>^
替代项时,这没有明显的效果,但它避免在其他替代项匹配时消除换行符。 - 逗号(
,
)用作模式分隔符,因此替换文本中的斜线(/
)不需要转义。 g
标志用于导致所有 次出现的模式被替换,而不仅仅是第一个。
如果你愿意依赖 GNU 扩展,那么你可以做的更简单一点:
sed -e '/==OPEN==/ {:loop; N; /==CLOSE==/! b loop; /id: class8/ {s,^,// ,gm}}' \
/example
使用 GNU sed
,s
命令中的 m
标志导致 ^
在模式 space 的开头和立即匹配在每个换行符之后。此标志未由 POSIX.