Попытка втиснуть в заголовок все следующее было трудным делом, поэтому я действительно имею в виду следующее:

Я делаю tail -F access.log чтобы посмотреть журнал Apache2 в режиме реального времени. Первое в каждой строке - это IP-адрес, за которым следует пробел. У меня также есть неизменный файл CSV, где каждая строка - это IP-адрес, запятая, имя. Например:

10.1.2.33,John Smith
10.1.2.190,Jane Doe

Доставляется: я хочу следить за своим журналом доступа, как и раньше, но если CSV-файл содержит строку с тем же IP-адресом, с которого начинается текущая строка файла журнала, то введите имя человека в начале строки.

Например, такая строка:

10.1.2.33 - - [22/Aug/2013:13:41:24 +0000] "GET /index.php ...

Вместо этого следует отобразить как:

John Smith 10.1.2.33 - - [22/Aug/2013:13:41:24 +0000] "GET /index.php ...

В идеале я хотел бы сделать это полностью, объединив несколько команд регулярных выражений. Пока что моя самая большая проблема заключается в том, что grep не принимает шаблон на stdin, он ожидает объект на stdin (если я что-то упустил). Кроме того, у меня нет проблем с преобразованием CSV в какой-то лучший формат при необходимости. Благодарю.

3 ответа3

1

Я бы сделал это с небольшим скриптом Perl:

#!/usr/bin/env perl

## Open the first argument, the .csv file
 open($f,"<","$ARGV[0]"); 
## Collect the list of ips and names in the %ips hash
 while(<$f>){
    chomp;
    @a=split(/,/); 
    $ips{$a[0]}=$a[1]
 }
## Now open the second argument, the log file to be watched. The
## trick here is to open by piping through tail -F
 open($f,"-|", "tail -F $ARGV[1]");
 while(<$f>){
 ## Get the ip
  /^([\d\.]+)/; 
  $ip=$1; 
 ## Prepend the associated name from the .csv file if one is defined
  s/$ip/$ips{$ip} $ip/ if defined($ips{$ip});
 ## Print the line
  print;
}

Сохраните это в вашем $ PATH как ip2name.pl , сделайте его исполняемым (chmod +x ip2name.pl) и затем запустите его так:

ip2name.pl /home/foo/ips.csv /var/log/apache2/access.log
1

Вот решение оболочки POSIX

tail -f access.log | while read -r line;do
    ip=${line%% *}
    name=$(grep -F "$ip" your_csv_file|cut -d, -f2)
    if [ -z "$name" ];then
        printf "%s\n" "$line"
    else
        printf "%s\n" "$name $line"
    fi
done

редактировать

Внесены два улучшения в решение:

  • для -r добавлен ключ read чтобы он не оценивал escape-последовательности в строках, которые он читает
  • -F добавлен в grep чтобы он рассматривал IP как фиксированную строку, а не как регулярное выражение.
0

grep может получить шаблоны из stdin, но не может получить текст из stdin одновременно. Смотрите опцию -f . Если ваша оболочка поддерживает подстановку процессов, вы можете смоделировать ее с помощью

produce_patterns | grep -f- <( produce_input )

Например:

( echo b; echo y ) | grep -f- <( for i in {a..z} ; do echo $i ; done )

Выход:

b
y

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .