将文件的内容与命令输出进行比较,然后执行命令并追加文件

时间:2012-08-04 15:42:16

标签: bash command-line awk

1。文件

文件/etc/ssh/ipblock包含如下所示的行:

2012-01-01 12:00 192.0.2.201
2012-01-01 14:15 198.51.100.123
2012-02-15 09:45 192.0.2.15
2012-03-12 21:45 192.0.2.14
2012-04-25 00:15 203.0.113.243

2。命令

命令iptables -nL somechain的输出如下所示:

Chain somechain (2 references)
target     prot opt source               destination
DROP       all  --  172.18.1.4           anywhere
DROP       all  --  198.51.100.123       anywhere
DROP       all  --  172.20.4.16          anywhere
DROP       all  --  192.0.2.125          anywhere
DROP       all  --  172.21.1.2           anywhere

第3。手头的任务

  1. 首先,我想获得iptables链(字段4)中存在的IP地址列表A,但不在文件中。
  2. 然后我想获得一个IP地址列表B,该列表存在于文件中但不存在于iptables链中。
  3. 然后,列表A中的IP地址应以相同的样式(日期,时间,IP)附加到文件中
  4. 然后应将列表B中的IP地址添加到带有
    的iptables链中 iptables -A somechain -d IP -j DROP
  5. 4。背景

    我希望扩展我的awk-fu,所以我一直试图使用一个可以在没有参数的情况下执行的awk脚本。但我失败了。

    我知道我可以使用getline命令从命令中获取输出,这样我就可以获得时间和日期。我也知道可以使用getline foo < file读取文件。但是我只有很多次尝试将这些内容组合成一个有效的awk脚本。

    我意识到我可以使用其他编程语言或shell脚本。但这可以通过一个可以不带参数运行的awk脚本来完成吗?

2 个答案:

答案 0 :(得分:3)

我认为这几乎就是你要找的东西。这个工作,一个文件,代码我猜是几乎不言自明...... 易于适应,可扩展...

<强> USAGE:
./foo.awk CHAIN ip.file

<强> foo.awk:

#!/usr/bin/awk -f
BEGIN {
    CHAIN= ARGV[1]
    IPBLOCKFILE = ARGV[2]

    while((getline < IPBLOCKFILE) > 0) {
        IPBLOCK[$3] = 1
    }

    command = "iptables -nL " CHAIN
    command |getline
    command |getline
    while((command |getline) > 0) {
        IPTABLES[$4] = 1
    }
    close(command)

    print "not in IPBLOCK (will be appended):"
    command = "date +'%Y-%m-%d %H:%M'"
    command |getline DATE
    close(command)
    for(ip in IPTABLES) {
        if(!IPBLOCK[ip]) {
            print ip
            print DATE,ip >> IPBLOCKFILE
        }
    }

    print "not in IPTABLES (will be appended):"
    # command = "echo iptables -A " CHAIN " -s " //use for testing 
    command = "iptables -A " CHAIN " -s "
    for(ip in IPBLOCK) {
        if(!IPTABLES[ip]) {
            print ip
            system(command ip " -j DROP")
        }
    }
    exit
}

答案 1 :(得分:1)

做1&amp; 3:

comm -13 <(awk '{print $3}' /etc/ssh/ipblock | sort) <(iptables -nL somechain | awk '/\./{print $4}' | sort) | xargs -n 1 echo `date '+%y-%m-%d %H:%M'` >> /etc/ipblock

做2&amp; 4:

comm -13 <(awk '{print $3}' /etc/ssh/ipblock | sort) <(iptables -nL somechain | awk '/\./{print $4}' | sort) | xargs -n 1 iptables -A somechain -d IP -j DROP

该命令由以下构建块构成:

  1. Bash进程替换功能:它有点类似于管道功能,但通常在程序在其参数/选项中需要两个或更多输入文件时使用。 Bash创建fifo文件,它基本上“包含”给定命令的输出。在我们的例子中,输出将是ip地址。
  2. 然后将awk脚本的输出传递给comm程序,两个awk脚本都非常简单:它们只是打印ip地址。在第一种情况下,所有ips都包含在第三列中(因此$3),而在第二种情况下,所有ips都包含在第四列中,但是必须删除列标题(“destination”字符串),如此简单的正则表达式使用/\./:它过滤掉所有不包含点的字符串。
  3. comm要求对两个输入进行排序,因此使用awk
  4. sort的输出进行排序
  5. 现在comm程序收到两个ip地址列表。如果没有给出选项,它会打印三列:FILE1独有的行,FILE2独有的行,两个文件中的行。通过将-23传递给它,我们只获得FILE1唯一的行。同样,传递-13会使输出行对FILE2唯一。
  6. xargs基本上是bash中的“foreach”循环,它为每个输入行执行一个给定的命令(感谢-n 1)。第二个是非常明显的(这是所需的iptables调用)。第二个也不复杂:它只是让date以适当的格式输出当前时间。