在日志文件中找到模式后提取 IP 地址

Extract IP address after pattern is found in log file

我需要在 bash 脚本中使用 ipset 命令提取并阻止日志文件中的某个 IP 地址(仅限 IPv4)。日志文件结构如下所示:

[Line 1] random text
[Line 2] random text
...
[Line 26] random text
Aug 31 13:40:14 [logs ] con_accept: [759] connection from 127.0.0.1:56860 is successfull on 0.0.0.0:25000
[Line 28] random text
...
[Line 38] random text
Aug 31 13:40:57 [logs ] _authrequest: [759] random text client connected and the sky is blue today more random text
[Line 40] random text

到目前为止,我是 grepawk 用法。找到模式后检查最后 15 行很容易,但是,我正在尝试进行额外检查并在 string is foundclientID 匹配后提取正确的 IP 地址。

awk 'c-->0;[=11=]~s{if(b)for(c=b+1;c>1;c--)print r[(NR-c+1)%b];print;c=a}b{r[NR%b]=[=11=]}' b=15 s="sky is blue" logfile

grep -B 15 'sky is blue' logfile

当您使用 awk 时,您永远不需要额外的 grep(或 sed)。

如果您的系统上有 tac 那么:

$ cat tst.sh
#!/usr/bin/env bash

ip=$(
    tac "${@:--}" |
    awk -v b=15 -v s='sky is blue' '
        [=10=] ~ s {
            endNr = NR + b
            id = 
        }
        ( == "con_accept:") && ( == id) {
            sub(/:.*/,"",)
            ip = 
        }
        NR == endNr { exit }
        END {
            if ( ip == "" ) {
                exit 1
            }
            else {
                print ip
            }
        }
    '
) &&
echo ipset add blacklist "$ip"

$ ./tst.sh file
ipset add blacklist 127.0.0.1

否则使用 GNU awk 处理数组数组的效率较低:

$ cat tst.sh
#!/usr/bin/env bash

ip=$(
    awk -v b=15 -v s='sky is blue' '
        { id =  }
         == "con_accept:" {
            sub(/:.*/,"",)
            ips[NR][id] = 
        }
        [=12=] ~ s {
            for (n=NR-1; n>(NR-b); n--) {
                if ( (n in ips) && (id in ips[n]) ) {
                    ip = ips[n][id]
                    exit
                }
            }
        }
        END {
            if ( ip == "" ) {
                exit 1
            }
            else {
                print ip
            }
        }
    ' "${@:--}"
) &&
echo ipset add blacklist "$ip"

$ ./tst.sh file
ipset add blacklist 127.0.0.1

当您完成测试并对结果感到满意时,请删除 echo

以上假定您问题中每行开头的 [Line N] 字符串实际上并不存在。如果是,则可以轻松调整为每个字段编号使用添加 2。

简单的第一关:

grep -nB 15 'sky is blue' logfile | sort -nr

grep -n 将在每一行前面加上文件中的行号(格式:<line_number>:<contents_of_line>)。

sort -rn 将使用数字排序以相反的顺序对行进行排序。

从这里您可以将这些行传递给 bash/while 循环或 awk 脚本,请记住几个(潜在的)问题:

  • 找不到'sky is blue'怎么办?
  • 如果 'sky is blue' 有多个匹配项怎么办?处理第一个、最后一个或所有实例?
  • 如果给定的 clientID 有多个匹配行但 IP 地址不同怎么办?处理第一个、最后一个或所有 IP 地址?
  • 是否所有感兴趣的行都具有与示例数据中显示的完全相同的格式,还是可能需要编码的格式不同?

'当然,所有这些都可以通过单个 awk 脚本(例如,Ed Morton 的回答)以多种不同的方式编码...