我有大约 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";
}
让我的眼睛少流血,但也许这只是我的感觉 :-)