从一行文本中的两个或更多 IP 地址中提取 1 个

从一行文本中的两个或更多 IP 地址中提取 1 个

我有大约 30,000 条 Apache 访问日志,其中一些列出了多个客户端 IP 地址。这是因为 Apache 记录的是 X-Forwarded-For 标头,而不是客户端的 IP 地址。这样做的原因是,我们最近在 Web 服务器前面添加了 haproxy。

未来我们将使用武装部队Apache 仅记录 1 个 IP 地址,即到 haproxy 的传入连接的 IP 地址,因此这不会成为一个持续的问题。

这让我想到了真正的问题:

我该如何处理具有多个 IP 地址的现有日志,以便仅提取我想要的那个。我假设我需要 sed 或类似的东西,但我更喜欢 Windows,所以不是 100% 确定。

规则如下:

  • 如果只有 1 个 IP,则不修改该行。
  • 如果有 2 个或更多 IP,我只想保留倒数第二个 IP。它们以逗号分隔。

示例 1,1 IP

输入:10.1.1.1 - - [29/Jan/2010:11:00:00] ....(日志行其余部分)

输出:10.1.1.1--[29/Jan/2010:11:00:00]... (日志行的其余部分)

示例 2,2 个 IP

输入:10.1.1.1, 10.2.2.2 - - [29/Jan/2010:11:00:00] .... (日志行其余部分)

输出:10.1.1.1- - [29/Jan/2010:11:00:00] ....(日志行剩余部分)

示例 3,3 个 IP

输入:10.1.1.1,10.2.2.2, 10.3.3.3 - - [29/Jan/2010:11:00:00] .... (日志行其余部分)

输出:10.2.2.2- - [29/Jan/2010:11:00:00] ....(日志行剩余部分)

答案1

这可以通过在日志上运行此 sed 命令来实现:

sed -i "s/^\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+, \)*\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\), [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+ - -/\2 - -/"

一些解释:

  • 一般格式是s/MATCH PATTERN/REPLACE PATTERN/
  • 匹配基于字符串“some IP, ”(0 到多次),后跟“some IP, ”(这是我们想要保留的),最后是“some IP - - ”(要丢弃的最后一个 IP)
  • 第一行格式(仅一个IP)不需要匹配,因为它不需要改变。
  • 最后一部分包含\2括号中指比赛的第二部分。
  • 在 shell 中运行时,许多字符必须转义(使用反斜杠:),例如括号:(),加号:(+表示“至少一次”)和文字字符句点:(.否则将被视为通配符)
  • sed 的选项-i意味着在原地更改文件。请确保您在副本上进行操作!

答案2

“它让我的眼睛几乎像 Perl 一样流血,但它确实有效。”

use strict;
use warnings;
use Regexp::Common qw /net/;

my $ip;
my $restOfLine;
my @ips;    

while (<>) {
    if (/- -.*/) {
        $restOfLine = $&;
    }
    unless (@ips = /($RE{net}{IPv4})/g) {
        print;
        next;
    }
    if ($ips[1]) {
        $ip = splice(@ips,-2,1);
    } else {
        $ip = $ips[0];
    }
    print "$ip " . $restOfLine . "\n";
}

让我的眼睛少流血,但也许这只是我的感觉 :-)

相关内容