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

时间:2013-10-04 22:19:06

标签: linux perl bash sed awk

我在/var/tmp/下跟随.xml个随机文件,我的行只包含:cidr=x.x.x.x/32x.x.x.x,现在我需要搜索IP并替换他们喜欢添加/编辑/ 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

OR

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 个答案:

答案 0 :(得分:3)

您不需要六个管道和各种命令,只需使用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

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

答案 1 :(得分:2)

此行适用于您的示例:

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" >

答案 2 :(得分:1)

因为你标记了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);
}