找到匹配项后,awk替换整行

时间:2015-03-15 21:17:09

标签: regex bash shell awk debian

我有以下代码:

function replaceappend() {
    awk -v old="^$2" -v new="$3" '
        sub(old,new) { replaced=1 }
        { print }
        END { if (!replaced) print new }
    ' "$1" > /tmp/tmp$$ &&
    mv /tmp/tmp$$ "$1"
}

replaceappend "/etc/ssh/sshd_config" "Port" "Port 222"

它完美无缺,但我希望修改它,以便它取代整行内容而不仅仅是匹配的文本。

目前它会这样做:

Port 1234 -> Port 222 1234

我希望它能像这样工作:

Port 1234 -> Port 222

我找到的最接近的代码是here

awk 'NR==4 {$0="different"} { print }' input_file.txt

这将用新内容替换匹配的整行。如何将其实现到我现有的代码中?

3 个答案:

答案 0 :(得分:2)

如果要更换整条线,可以简化功能。为了避免传递给awk的变量中的元字符问题,我建议使用简单的字符串搜索:

awk -vold="$2" -vnew="$3" 'index($0,old)==1{f=1;$0=new}1;END{if(!f)print new}' "$1"

index返回您要搜索的字符串的字符位置,从1开始。如果字符串old位于该行的开头,则该行将更改为new。块之后的1始终为true,因此每行都打印出来(这是无条件{print}块的常用简写。)

正如mklement0在注释中指出的那样,传递给awk的变量仍然需要进行一些解释:例如,字符串\n将被解释为换行符{{1然而,这个问题远不如使用正则表达式那么重要,正如\t之类的东西会匹配任何字符。

答案 1 :(得分:2)

只需改变:

sub(old,new) { replaced=1 }

为:

$0~old { $0=new; replaced=1 }

或:

sub(".*"old".*",new) { replaced=1 }

答案 2 :(得分:1)

同样,使用正则表达式来替换它:

replaceappend port.txt "Port.*" "Port 222"

在这里你要替换Port(如果它根据你的函数定义开始行)以及随后的任何内容,直到行结束时使用" Port 222"。

编辑:要将此部分功能转换为通话,请将其修改为

function replaceappend() {
    awk -v old="^$2.*" -v new="$3" '                                                                                                        
        sub(old,new) { replaced=1 }                                                                                                         
        { print }                                                                                                                           
        END { if (!replaced) print new }                                                                                                    
    ' "$1" > /tmp/tmp$$ &&
    mv /tmp/tmp$$ "$1"
}