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

我有大约30,000个Apache访问日志,其中一些列出了多个客户端IP地址。 这是由于Apachelogging了X-Forwarded-For头而不是客户端的IP地址。 之所以这样做,是因为我们最近在web服务器前加了haproxy。

outlook未来,我们将使用Apache的rpaf来logging只有一个IP地址,即到haproxy的连接,所以这不会是一个持续的问题。

这给我带来了实际的问题:

如何处理多个IP地址的现有日志,只提取我想要的日志。 我假设我需要sed或类似的,但我更像一个Windows的家伙,所以不是100%肯定。

规则是:

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

实例1,1IP

input:10.1.1.1 – – [29 / Jan / 2010:11:00:00] ….(其余的日志行)

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

示例2,2个IP

input: 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

input: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] ….(其余的日志行)

这可以通过在日志中运行此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/
  • 匹配是在string“some IP”(0到很多次)之后进行的,然后是“some IP”(这是我们想要保留的),最后是“some IP – – ”(丢弃的最后一个IP)
  • 不需要匹配第一行的格式(只有一个IP),因为它不需要改变。
  • 最后一部分包含\2 ,其中括号中的第二部分是指匹配。
  • 当在一个shell中运行时,许多字符必须被转义(带有反斜杠:),如括号() ,加号: + (意思是“至less一次”)和字面字符句号: . (否则它被认为是通配符)
  • sed的-i选项意味着更改文件。 确保你在拷贝上工作!

“这使得我的眼睛几乎和Perl一样stream血,但是它很有效。”

 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"; } 

让我的眼睛stream血less,但也许这只是我:-)