代码之家  ›  专栏  ›  技术社区  ›  user285594

BASH-如何从整个目录中搜索一个值并找到一些匹配的值,然后通过保存来动态替换该行

  •  1
  • user285594  · 技术社区  · 12 年前

    我有不足 /var/tmp/ 随机跟随 .xml 文件,在那里我有这样的行包含: cidr=x.x.x.x/32 x.x.x.x 只是,现在我需要搜索一个IP并像add/edit/del一样替换它们。

    之前:

    file1.xml: <user id="1" cidr="192.168.1.12">
    file2.xml: <user id="2" cidr="192.168.1.12,192.168.1.13">
    file3.xml: <user id="3" cidr="8.8.8.8">
    file4.xml: <user id="4" cidr="8.8.8.8/32">
    fileX.xml: <user id="5" cidr="192.168.1.12/32">
    

    之后 (预期输出):

    file1.xml: <user id="1" >
    file2.xml: <user id="2" cidr="192.168.1.13">
    file3.xml: <user id="3" cidr="8.8.8.8">
    file4.xml: <user id="4" cidr="8.8.8.8/32">
    fileX.xml: <user id="5" >
    

    现在,为了找到哪一行包含匹配的ip,然后替换它,我试着在一行中这样做:

    grep -R 'cidr=' ./*.xml              # search in whole directory
    | awk '/192.168.1.12/ {print $1}'    # find for a given search criteria 
    | sed 's/^.\///g'                    # replace some not necessary values
    | sed 's/://'                        # ..
    | xargs sed -i s/""/""/ /var/tmp/    # on the fly workout on that line 
                                         # + save it to that file
    

    grep -R 'cidr=' ./*.xml              # search in whole directory
    | awk '/192.168.1.12/ {print $1}'    # find for a given search criteria 
    | sed 's/^.\///g'                    # replace some not necessary values
    | sed 's/://'                        # ..
    | ( grep -R 'cidr=' ./*.xml 
        | awk '/192.168.1.12/ {print $4}' 
        | sed 's/ //g' 
      ) 
    | xargs sed -i s/""/""/ /var/tmp/    # on the fly workout on that line 
                                         # + save it to that file
    

    但似乎并不像预期的产出那样奏效。

    3 回复  |  直到 12 年前
        1
  •  2
  •   Ed Morton    12 年前

    您不需要六个管道和各种命令,只需使用find查找文件并使用awk进行修改即可,例如:

    find /var/tmp/ -type f -name '*.xml' -print |
    while IFS= read -r file
    do
        awk '
            <whatever>
        ' "$file" > tmp$$ && mv tmp$$ "$file"
    done
    

    下面是编写awk脚本的方法:

    $ cat file
    file1.xml: <user id="1" cidr="192.168.1.12">
    file1.xml: <user id="1" cidr="192.168.1012">
    file1.xml: <user id="1" cidr="192.168.1.123">
    file2.xml: <user id="2" cidr="192.168.1.12,192.168.1.13">
    file2.xml: <user id="2" cidr="192.168.1.13,192.168.1.12">
    file2.xml: <user id="2" cidr="192.168.1.13,192.168.1.12,8.8.8.8">
    file3.xml: <user id="3" cidr="8.8.8.8">
    file4.xml: <user id="4" cidr="8.8.8.8/32">
    fileX.xml: <user id="5" cidr="192.168.1.12/32">
    
    $ awk -v tgtIp="192.168.1.12" '
    BEGIN {
        gsub(/\./,"\\.",tgtIp)
        tgtIp  = tgtIp "(/[[:digit:]]+)?"
        tgtIp = "(," tgtIp "\\>)|(\\<" tgtIp ",)|(\\<" tgtIp "\\>)"
    }
    match($0,tgtIp) {
        $0 = substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH)
        sub(/cidr=""/,"")
    }
    { print }
    ' file
    file1.xml: <user id="1" >
    file1.xml: <user id="1" cidr="192.168.1012">
    file1.xml: <user id="1" cidr="192.168.1.123">
    file2.xml: <user id="2" cidr="192.168.1.13">
    file2.xml: <user id="2" cidr="192.168.1.13">
    file2.xml: <user id="2" cidr="192.168.1.13,8.8.8.8">
    file3.xml: <user id="3" cidr="8.8.8.8">
    file4.xml: <user id="4" cidr="8.8.8.8/32">
    fileX.xml: <user id="5" >
    

    因此整个shell脚本将是:

    find /var/tmp/ -type f -name '*.xml' -print |
    while IFS= read -r file
    do
        awk -v tgtIp="192.168.1.12" '
        BEGIN {
            gsub(/\./,"\\.",tgtIp)
            tgtIp  = tgtIp "(/[[:digit:]]+)?"
            tgtIp = "(," tgtIp "\\>)|(\\<" tgtIp ",)|(\\<" tgtIp "\\>)"
        }
        match($0,tgtIp) {
            $0 = substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH)
            sub(/cidr=""/,"")
        }
        { print }
        ' "$file" > tmp$$ && mv tmp$$ "$file"
    done
    

    您可能想尝试使用我上面使用的示例输入所考虑的任何其他解决方案。

        2
  •  1
  •   Kent    12 年前

    这一行适用于您的示例:

    grep...|awk '{gsub(/192.168.1.12[^,"]*[,"]/,"");sub(/cidr=">/,">")}7'
    

    小测试:

    kent$  cat f
    file1.xml: <user id="1" cidr="192.168.1.12">
    file2.xml: <user id="2" cidr="192.168.1.12,192.168.1.13">
    file3.xml: <user id="3" cidr="8.8.8.8">
    file4.xml: <user id="4" cidr="8.8.8.8/32">
    fileX.xml: <user id="5" cidr="192.168.1.12/32">
    kent$  awk '{gsub(/192.168.1.12[^,"]*[,"]/,"");sub(/cidr=">/,">")}7' f
    file1.xml: <user id="1" >
    file2.xml: <user id="2" cidr="192.168.1.13">
    file3.xml: <user id="3" cidr="8.8.8.8">
    file4.xml: <user id="4" cidr="8.8.8.8/32">
    fileX.xml: <user id="5" >
    
        3
  •  0
  •   Jean    12 年前

    由于您标记了Perl

    ls *xml | xargs script.pl
    

    脚本:

    #!/usr/bin/perl 
    
    use strict;
    use warnings;
    my $ip = '192.168.1.12' ;
    foreach my $file (@ARGV)
    {
        open(FILE,$file);
        while(<FILE>)
        {
            s/(cidr="$ip\/32"|cidr="$ip"|$ip,)//;
            print "$file: $_";
        }
        close(FILE);
    }