如何用sed/Bash无环视正则匹配行首目标短语而非行内短语
问题描述
我有一个名为test的文件,内容如下:
foo bar baz foo or bar foo or baz bar or baz
需求是:在每个foo、bar、baz短语前添加单个逗号,但不能匹配包含or的行中位于or之后的这些短语。当前在Bash环境中使用sed工具,也接受其他Bash解决方案并需附带说明,已知sed不支持环视功能。
我目前使用的命令及输出如下:
# this places comma before each baz sed -e 's/\(baz\)/,\1/g' test
输出结果:
foo bar ,baz foo or bar foo or ,baz bar or ,baz
期望的输出为:
,foo ,bar ,baz ,foo or bar ,foo or baz ,bar or baz
另外,直接在每行开头添加逗号不符合我的最终需求,请仅提供与正则相关的解决方案。
解决方案
1. 使用sed实现
写法一:分条件匹配不同行
sed -e '/or/ s/^\(foo\|bar\|baz\)/,\1/' -e '/^[^o][^r]*$/ s/^\(foo\|bar\|baz\)/,\1/' test
说明:
- 第一个规则:匹配包含
or的行,仅对行首的foo/bar/baz添加前缀逗号; - 第二个规则:匹配不包含
or的行(通过正则确保整行无"or"字符串),对行首的目标短语添加前缀逗号。
写法二:先全局处理再修正
sed 's/^\(foo\|bar\|baz\)/,\1/; /or/!b; s/,\(foo\|bar\|baz\) or/\1 or/' test
说明:
- 第一步:给所有行首的
foo/bar/baz添加逗号; - 第二步:仅对包含
or的行,把or前面错误添加的逗号移除(保证只有行首的短语带逗号)。
写法三:优先匹配带or的行结构
sed -e 's/^\(foo\|bar\|baz\)\( or .*\)/,\1\2/' -e 's/^\(foo\|bar\|baz\)/,\1/' test
说明:
- 第一个规则:优先匹配带
or的行,捕获行首目标短语和后续的or ...部分,给行首短语加逗号后拼接; - 第二个规则:处理不带
or的单行短语,直接添加前缀逗号。
2. 使用awk实现
如果觉得sed的正则逻辑较复杂,可以用awk的条件判断简化:
awk '{if (/or/) sub(/^foo|^bar|^baz/, ",&"); else sub(/foo|bar|baz/, ",&")} 1' test
说明:
- 对包含
or的行:只替换行首的目标短语(用^限定匹配范围); - 对不包含
or的行:直接替换唯一的目标短语; - 末尾的
1用于输出处理后的每一行。
内容的提问来源于stack exchange,提问作者code_cowboy
相关产品推荐
相关产品推荐

