文件中有两行,如下所示:
#foo:
# bar=<need replacement>
当第一行以foo
开头,第二行包含bar
并替换<>
之间的文本时,我想删除#
,如果它存在(取消行注释)。
我可以在使用sed的N;P;D
周期的一次传递中做到这一点吗?或者还有其他更简单的方法吗?
这可能适合您(GNU sed):
sed -E '/^#?foo/{N;/n.*bar/{s/^#//mg;s/(n.*<).*(>.*)/1replace2/};P;D}' file
如果当前行以foo
注释或未注释开始,则:
添加以下行
如果下面一行包含单词
bar
,则:- 删除任意两行开头的
#
。 - 将第二行
<
和>
之间的字符替换为replace
。
- 删除任意两行开头的
打印/删除第一行并重复。
注意:这允许处理前导foo
,然后是另一个前导foo
,然后是bar
。
使用带有标准N;…;P;D;
循环和基本正则表达式的POSIX sed(BRE):
sed -e '$!N' -e '/^#(foo:n)#([[:blank:]]*bar)=.*/ s//12=newvalue/' -e P -e D < file
这可能是可以做到的,但我会使用不同的工具。Awk怎么样?
awk -v replace="new value" 'm && /^[^:]+:/ { m=0 }
/^#foo:/ { m=1 }
m { sub(/^#/, ""); s(/<[^<>]*>/, replace) }1'
这遵循了我们熟悉的模式:当我们看到感兴趣的区域开始时设置状态变量m
,当我们在该区域时执行替换,当我们看到新区域开始时关闭变量(推测其条件可能是什么样子)。
要改变这一点并不难,只需在区域开始后查找固定数量的行;将状态变量设置为一个数字,并每行递减。
如果这是一个Makefile,那么使用make
变量会更加优雅和健壮。
ifdef ENABLE
foo:
bar=$(barvalue)
endif
(或者仅仅是ifdef barvalue
!)