1

我有/var/tmp/ 以下随机.xml文件,并且我有这样的行包含: cidr=x.x.x.x/32x.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

但似乎不像预期的输出那样工作。

4

3 回答 3

2

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

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

于 2013-10-05T13:04:14.803 回答
1

此行适用于您的示例:

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" >
于 2013-10-04T22:31:56.160 回答
0

既然你标记了 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);
}
于 2013-10-04T23:22:14.380 回答