[英]Regex find and replace over multi lines in Shell
我的问题与shell 脚本类似:搜索和替换多行,但有一个小例外。
在链接的问题中,用户想要这样做:
source:
[stuff before]
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
[stuff here, possibly multiple lines.
<!--WIERD_SPECIAL_COMMENT_END-->
[stuff after]
target:
[stuff before]
[new content]
[stuff after]
我的问题类似,我想这样做:
source:
[stuff before]
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
[this]
<!--WIERD_SPECIAL_COMMENT_END-->
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
[not this]
<!--WIERD_SPECIAL_COMMENT_END-->
[stuff after]
target:
[stuff before]
[new content]
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
[not this]
<!--WIERD_SPECIAL_COMMENT_END-->
[stuff after]
在适当的多行正则表达式中,这很容易做到:
/<!--WIERD_SPECIAL_COMMENT_BEGIN-->.*[this].*<!--WIERD_SPECIAL_COMMENT_END-->/m
但是链接问题中建议的答案使用正则表达式作为不允许检查两个外围边界之间的线的范围。
有没有办法将一个范围内的所有行添加到模式缓冲区,以便我可以一次对所有行进行正则表达式? 例如:
sed '
#range between comment beginning and comment end
/<!--WIERD_SPECIAL_COMMENT_BEGIN-->/,/<!--WIERD_SPECIAL_COMMENT_END-->/
#Do something to add the lines in this range to pattern buffer
/.*[this].*/d
#Delete all the lines if [this] is in the pattern buffer
' <in.txt >out.txt
使用 Perl,它相对简单。
perl -0777pe 's/<!--BEGIN-->\n(?:(?!<!--END-->\n).)*?\[this\].*?\n<!--END-->\n/[new content]\n/s' in.txt
Perl 提供的好处是 (a) -0777
“slurp 模式”,它一次性拉入整个输入文件,而不是sed
的一次一行处理; (b) 允许点匹配换行符的/s
正则表达式标志; (c) 吝啬的重复运算符*?
和朋友,这导致重复尽可能少而不是尽可能多地匹配; 最后是 (d) 否定前瞻(?!...)
,它允许您在否定前瞻表达式匹配的地方禁止匹配。 (没有这个,如果在“stuff before”文本中有一个“假”的起始分隔符,即使是吝啬的匹配也会匹配结束分隔符。)......当然,(e)一种通用编程语言,其中sed
是只适合比较简单的文本处理任务。
(我使用了更简单的开始和结束分隔符。我希望“奇怪”是故意拼写错误。)
免责声明:我是初学者。 这肯定不是最好的方法。
我分三步做了类似的事情。 假设您在 Linux 上运行,您可以执行以下操作:
1)用特殊字符替换文件中所有出现的换行符:
cat originalText.txt | tr '\n' '~' > temp
2)使用您最喜欢的方法(我使用perl)执行您的正则表达式,在您期望换行符的每个位置放置一个特殊字符的实例。 确保保持特殊换行符不变。
3)这次以相反的方式执行第一个命令:
cat temp | tr '~' '\n' > modText.txt
我希望这有帮助。
有没有办法将一个范围内的所有行添加到模式缓冲区,以便我可以一次对所有行进行正则表达式?
当然,使用保持空间。 例如:
sed -n '/begin/,/end/{ /begin/{h;d};H}; /end/{g;s/\n/<newline>/gp}'
将用文本<newline>
替换匹配 'begin' 和 'end' 的行之间的换行符
这可能对您有用(GNU sed):
sed ':a;$!N;/^<!--WIERD_SPECIAL_COMMENT_BEGIN-->/!{P;D};/<!--WIERD_SPECIAL_COMMENT_END-->$/!ba;s/\[this\]/[new content]/;p;d' file
您可以使用sed
这样做:
解析.sed
/BEGIN/ { # If we encounter BEGIN
:a # Read all until END
N # into pattern space
/END/!ba # /
/\[this\]/d # If the block contains [this], delete it
s/^/[new content]\n/ # Insert [new content] before the block
}
像这样运行它:
sed -f parse.sed infile
输出:
[stuff before]
[new content]
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
[not this]
<!--WIERD_SPECIAL_COMMENT_END-->
[stuff after]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.