关于bash函数中Perl \K用法的异常问题咨询
为什么我的bash替换函数没得到预期结果?
咱们来一步步拆解问题:
首先看你的函数和执行命令:
function replace { ( perl -i -slpe 's/^$string.*\K/$add/' -- -string="$1" -add="$2" $3 ) } replace 'passwd:' 'files dns' /tmp/1
输入文件内容是passwd: files group: files,执行后得到passwd: filesfiles dns group: files,但你想要的是passwd: files dns group: files。
问题出在正则表达式的逻辑
你的perl正则s/^$string.*\K/$add/的行为和你预期的完全不一样:
^$string匹配行首的passwd:.*是贪婪匹配,会吃掉passwd:之后的所有内容直到行尾(如果是单行的话就是files group: files,如果是两行的话就是第一行的files)\K是perl的零宽度断言,作用是保留\K之前匹配到的所有内容,只替换\K之后的部分。但这里.*已经匹配到了行尾,\K后面没有内容,所以相当于在整行的末尾追加$add的值files dns。
如果你的输入文件其实是两行(passwd: files和group: files),那第一行末尾没有空格,直接追加files dns就会变成passwd: filesfiles dns,和你看到的结果一致。
怎么修改才能得到预期结果?
根据你的预期,你是想在passwd:后面的files后面添加 dns,而不是整行末尾追加。你需要调整正则表达式,精准定位到files的后面:
- 先修改你的函数里的正则:
function replace { ( perl -i -slpe 's/^$string\s+\S+\K/ $add/' -- -string="$1" -add="$2" $3 ) }
这里的正则解释:
^$string\s+:匹配行首的passwd:加上后面的空格\S+:匹配后面的第一个非空字段(也就是files)\K:保留前面的所有内容,然后在后面添加带空格的$add
- 调整执行命令的参数,因为原内容已经有
files,你只需要传递dns即可:
replace 'passwd:' 'dns' /tmp/1
这样执行后,输入文件里的passwd: files就会变成passwd: files dns,最终结果就是你想要的passwd: files dns group: files。
如果你确实想直接替换成files dns(比如原字段不是files),那可以用另一种正则来替换第一个字段:
function replace { ( perl -i -slpe 's/^($string\s+)\S+/\1$add/' -- -string="$1" -add="$2" $3 ) }
然后执行replace 'passwd:' 'files dns' /tmp/1,也能得到预期结果。
内容的提问来源于stack exchange,提问作者Sandra Schlichting
相关产品推荐
相关产品推荐

