найти правильный файл журнала из тысяч, используя head и fgrep

У меня есть тысячи файлов журнала – все очень большие. У одного из них будет IP-адрес, который я ищу. Я знаю, что это может произойти в верхней части файла. Я могу сделать:

head -n 500 *.log | fgrep myip 

и я увижу, что “да”, это в одном из файлов журнала. Как мне определить, какой? Извлечение полного содержимого (fgrep myip * .log) всех файлов невозможно из-за их размера.

Нечто подобное должно помочь.

 find . -iname "*.log" -print0 | xargs -0 -i{} bash -c 'echo "»»»File Name: {}«««"; head -n 500 {} | fgrep -B 501 myip' 

Он выдаст длинный список имен файлов, затем до 500 строк найденных данных, а затем длинный список имен файлов. Желаемое имя файла – это имя, которое находится непосредственно перед длинным списком данных.

Вы можете сойти с рук только с помощью awk:

 awk -v ip=127.0.0.1 'substr($0, ip) > 0 {print FILENAME ": " $0} FNR > 500 {nextfile}' *.log 

Если IP-адрес был найден в текущей строке, мы печатаем его и имя файла. Мы переходим к следующему файлу, если текущий номер строки для текущего файла ( FNR ) стал> 500.

 find -name \*.log -print0 | xargs -0 sh -c 'for i; do head -n 500 $i | fgrep -q myip && echo $i; done 

Это найдет все имена файлов, оканчивающиеся на .log , и xargs этот список в xargs . -print0 и xargs -0 обычно используются для использования нулевого байта для завершения имен файлов, для защиты имен файлов, содержащих пробелы (нулевой байт никогда не может использоваться в имени файла, поэтому является безопасным разделителем).

xargs запустит команду, заданную после xargs и ее аргументов, с таким количеством имен файлов, которое поместится в одном вызове команды. В этом случае указана команда sh (shell), и этой оболочке дан небольшой скрипт для запуска.

Сценарий оболочки в основном:

 for i; do head -n 500 $i | fgrep -q myip && echo $i done 

Часть for i перебирает все аргументы, данные оболочке, то есть все имена файлов. Для каждого имени файла он берет первые 500 строк и ищет данную строку. fgrep -q означает, что fgrep останавливается, как только строка найдена; если строка найдена, выдается статус выхода «success», иначе «fail». Наконец, && echo $i означает, что если предыдущая команда имеет статус «успех», эхо выполняется, что означает, что имя файла отображается, если найдена строка.

Я мог бы:

  1. перебрать все файлы
  2. захватить первые 500 строк
  3. посмотреть, есть ли IP в этих строках
  4. если это так, выведите имя файла и завершите цикл

Как код:

 for f in ./* do head -n 500 "$f" | grep -qF myip && { printf "Found in: $f"; break; } done 

Где вы могли бы заменить myip IP-адресом, который вы ищете. Вы можете создать функцию (или сценарий оболочки), которая принимает желаемый IP в качестве параметра для поиска:

 findlogip () { for f in ./*; do head -n 500 "$f" | grep -qF "$1" && { printf "Found in: $f\n"; break }; done } 

Как прокомментировал roaima , вы можете быть осторожны с искомым IP-адресом, чтобы случайно не сопоставить другой IP-адрес (10.55.33.6, но соответствует 110.55.33.68 в примере). С помощью GNU grep (предполагается, учитывая тег linux ) вы можете окружить данный IP-адрес маркерами \b :

 ... head -n 500 "$f" | grep -q "\b$1\b" && ... ... 

Вы удаляете опцию -F (фиксированная строка) grep, поскольку выражение больше не является «фиксированным», а является регулярным выражением.