【问题标题】:Extract IP address after pattern is found in log file在日志文件中找到模式后提取 IP 地址
【发布时间】:2021-10-31 01:51:25
【问题描述】:

我需要在 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
  • 忘记添加每行[Line 1] ... [Line X 以时间戳Aug 31 13:40:14 [logs ] con_accept: [759] connection from 127.0.0.1:56860 is successful on 0.0.0.0:25000 开头
  • 需要提取和阻止的 IP 地址将显示在与模式匹配的行之前的最后 15 行内。在这种情况下,可以在Line 27 找到。
  • 脚本首先搜索sky is blue字符串
  • 找到字符串后,它会在匹配的字符串行之前打印最后一个15 lines,并提取与[759]匹配的IP地址,即clientID
  • 为避免误报和错误块,[ID] 必须匹配,在这种情况下,[759] 匹配 Line 39 and Line 27clientID 不是预定义的数字,所以它会改变。只能是数字。
  • IPv4 地址127.0.0.1 将被提取,然后使用ipset add blacklist $IP 阻止

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

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

grep -B 15 'sky is blue' logfile

【问题讨论】:

    标签: awk grep


    【解决方案1】:

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

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

    $ cat tst.sh
    #!/usr/bin/env bash
    
    ip=$(
        tac "${@:--}" |
        awk -v b=15 -v s='sky is blue' '
            $0 ~ s {
                endNr = NR + b
                id = $2
            }
            ($6 == "con_accept:") && ($7 == id) {
                sub(/:.*/,"",$5)
                ip = $10
            }
            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 = $7 }
            $6 == "con_accept:" {
                sub(/:.*/,"",$10)
                ips[NR][id] = $10
            }
            $0 ~ 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 是一个简单的调整。

    【讨论】:

    • 谢谢你,@Ed Morton。我认为这就是脚本目前失败的原因,因为每一行都以以下格式的时间戳开头Aug 31 13:40:14 [logs ] con_accept: [759] connection from 127.0.0.1:56860 is successful on 0.0.0.0:25000
    • 不要发布看起来不像您的真实数据的示例输入/输出,因为这会使我们更难帮助您解析您的真实数据。请edit您的问题显示一些更真正具有代表性的示例输入/输出。
    • 很抱歉,我一开始就把时间戳放在一边,忘了它可能会改变整个结果。我已经更新了适当的数据,包括random text,其中文本实际上是随机的。
    • 谢谢@Ed Morton,现在效果很好。由于客户端以后可以有不同的 IP 地址,是否可以在匹配字符串行之前的前 15 行中为与 string +clientID 匹配的所有 IP 地址运行脚本?
    • 不,只是说它是这个的后续(并提供它的链接)并说明差异,例如多次出现 IP 地址或“天空是蓝色的”或其他任何内容,您将显示不同的 minimal reproducible example 和不同的代码(我的加上你自己尝试做的任何事情来解决新问题)加上不同的示例输入/输出.
    【解决方案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' 有多个匹配项怎么办?处理第一个、最后一个或所有实例?
    • 如果给定的 clientID 有多个匹配的行但具有不同的 ip 地址怎么办?处理第一个、最后一个或所有 IP 地址?
    • 是否所有感兴趣的行都具有与示例数据中显示的完全相同的格式,或者是否有不同的格式需要编码?

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

    【讨论】:

    • 如果没有找到sky is blue,只需忽略该脚本。如果sky is blue 有多个匹配项,则处理所有实例。如果给定的 clientID 有多个匹配的行但具有不同的 IP 地址,则处理所有 IP 地址。如果这不可能,我可以在找到每个匹配项并运行脚本后截断日志文件。
    • @Brian-reins 请用这些额外的细节更新问题;不是每个人都会仔细阅读 cmets 试图拼凑整张图片
    • 对那个 markp 感到抱歉,我一开始就把时间戳放在一边,忘了它可能会改变整个结果。我已经更新了正确的数据,包括random text,其中文本实际上是随机的。
    • 我是指将您的 cmets 添加到问题中,回复:多次出现“天空是蓝色”和给定 clientID 的多个 ips(在最后 15 行内)
    • 谢谢markp。我确实给出了答案:“天空是蓝色的”多次出现,并且给定客户端 ID 的多个 ip 是可能的,但不是在最后 15 行内。 Ed 的解决方案就像一个魅力,只是脚本只处理第一个 IP 地址,我需要处理与 string + clientID 匹配的所有 IP 地址,因为 IP 地址可以不同。
    猜你喜欢
    • 1970-01-01
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    相关资源
    最近更新 更多