Извлечь 1 IP-адрес из 2 или более в строке текста
У меня есть около 30000 журналов доступа Apache, некоторые из которых содержат несколько IP-адресов клиентов. Это является результатом того, что Apache регистрирует заголовок X-Forwarded-For вместо IP-адреса клиента. Причина в том, что мы недавно добавили haproxy перед веб-серверами.
В дальнейшем мы будем использовать rpaf для Apache для регистрации только 1 IP-адреса, т. Е. Адреса входящего соединения с haproxy, поэтому это не будет постоянной проблемой.
Что подводит меня к актуальному вопросу:
Как я могу обработать существующие журналы с несколькими 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].... (остаток строки журнала)
2 ответа
Этого можно достичь, выполнив команду 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/
- Соответствие выполняется для строки "некоторый IP" (от 0 до много раз), за которой следует "некоторый IP" (это тот, который мы хотим сохранить) и, наконец, "некоторый IP - - " (последний IP-адрес, который следует отбросить)
- Нет необходимости соответствовать первому формату строки (только один IP), так как он не нуждается в изменении.
- Последний раздел содержит
\2
что относится ко второй части матча в скобках. - При запуске в оболочке многие символы должны быть экранированы (с обратной косой чертой:), например, в скобках:
(
а также)
плюс:+
(что означает "хотя бы один раз") и период буквального символа:.
(иначе это считается подстановочным знаком) -i
Опция sed означает изменение файлов на месте. Убедитесь, что вы работаете с копиями!
"Это заставляет мои глаза кровоточить почти так же, как 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";
}
Заставляет мои глаза кровоточить меньше, но, возможно, это только я:-)