我希望在特定模式匹配后删除"#"
。
例如:
在下面的代码中,我grep
代表"SOME DESC"
。我希望"SOME DESC"
上方和下方评论的所有行都得到未评论。
#define service {
# hostgroup_name hmaster_hosts
# use local-service
# servicegroups SOME_GROUP
# service_description SOME DESC : service Service
# check_command check_nrpe!check_something
#}
define service {
hostgroup_name hmaster_hosts
use local-service
servicegroups SOME_GROUP
service_description SOME DESC : service Service
check_command check_nrpe!check_something
}
我尝试使用以下代码进行更改。
sed -i 's/#define service {/define service {/g' services.cfg
sed -i 's/# hostgroup_name / hostgroup_name /' services.cfg
sed -i 's/# use / use /' services.cfg
sed -i 's/# servicegroups/ servicegroups/' services.cfg
sed -i 's/# service_description / service_description /' services.cfg
sed -i 's/# check_command / check_command /' services.cfg
sed -i 's/#}/}/g' services.cfg
但#
的位置在代码中是不确定的,即它可以是# hostgroup_name
或#hostgroup_name
或# hostgroup_name
所以我的方法dint适用于代码的某些部分。我想知道有没有更好的方法来做到这一点,无论#
答案 0 :(得分:2)
如果你有 GNU awk
,你可以尝试以下方法:
awk -v search='SOME DESC' -v RS='(^|\n)#define service \\{[^}]*\\#\\}\n' '
index(RT, search) { RT = gensub("(^|\n)#", "\\1", "g", RT) }
{ printf "%s%s", $0, RT }
' file
上面假设注释行直接从#
开始,代码紧跟在后面,如问题中的示例输入。对于使用可变数量的空格的变体解决方案,请参见底部。
这假设感兴趣的注释行是注释define service { ... }
行的块,如果在块内找到搜索字符串,则应该作为整体取消注释。
-v search='SOME DESC'
传递文字字符串以搜索为Awk变量search
。
-v RS='(^|\n)#define service \\{[^}]*\\#\\}\n'
将输入记录分隔符定义为RS
,作为以注释掉的define service {
行开头的正则表达式以注释掉的}
行结尾,后跟换行符。
这意味着当前记录在$0
中报告的数据包含每个感兴趣的块之前的行。
但是,GNU公开了RS
中的正则表达式通过(非标准)变量RT
匹配的实际记录终止符(分隔符)。因此,RT
的值包含每次迭代中感兴趣的块。
index(RT, search)
返回搜索字符串在当前块内的位置的从1开始的索引,如果块不包含搜索字符串,则返回0。当用作模式(布尔条件)时,关联的操作({...}
)仅在块包含搜索字符串时执行。
RT = gensub("(^|\n)#", "\\1", "g", RT)
删除评论字符。 (#
)从块中所有行的最开始
请注意gensub()
是GNU特定的函数,特别允许使用对捕获组的引用(\1
指的是匹配的捕获组(^|\n)
;需要额外的\
,因为awk
的字符串解析过程\
- 也是前缀转义序列。) { printf "%s%s", $0, RT }
打印当前记录($0
),后跟 - 可能未注释 - 阻止。
适用于可变数量空白的变体:
awk -v search='SOME DESC' -v RS='(^|\n)[[:blank:]]*#[[:blank:]]*define[[:blank:]]+service[[:blank:]]+\\{[^}]*\\#[[:blank:]]*\\}\n' '
index(RT, search) { RT = gensub("(^|\n)[[:blank:]]*#", "\\1", "g", RT) }
{ printf "%s%s", $0, RT }
' file
这与上面的解决方案基本相同,只是在#
匹配([[:blank:]]*
)之前和之后(可能是空的)空格/制表符的运行,并且非空的可变长度之间的运行define
行([[:blank:]]+
)的标记。