Мне нужно выполнить поиск по нескольким файлам журнала (все файлы, созданные за последние 24 часа, все они находятся в одном каталоге), чтобы найти последнее вхождение строки. Это команда, которую я написал:
find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1
Но это возвращает только последнюю строку для одного файла. Любые предложения о том, как настроить это, чтобы получить все строки?
bash
shell-script
text-processing
grep
Lokesh
источник
источник
Ответы:
Принимая во внимание возможности GNU:
источник
find
выполнять команды для файлов, используя-exec
. С помощьюbash -c
мы создаемbash
оболочку, которая просматривает файлы, найденныеfind
и выполняемыеtac .. | grep -m1 fileprefix
на каждом из них-d" "
с разрезом. Двойные кавычки вместо одинарныхfind
может фильтровать по префиксу файла; для этогоgrep
не нужно Также удивительно, что строка поиска не фигурирует в этом ответе.Если все в одном каталоге, вы можете сделать:
Если это большие файлы, возможно, стоит ускорить процесс, используя
tac
для печати файл в обратном порядке (сначала последнюю строку), а затемgrep -m1
для сопоставления с первым вхождением. Таким образом, вам не нужно читать весь файл:Оба из них предполагают, что нет подходящих каталогов
fileprefix
. Если есть, вы получите ошибку, которую можете просто проигнорировать. Если это проблема, проверьте только файлы:Если вам также нужно напечатать имя файла, добавляйте
-H
к каждомуgrep
вызову. Или, если вашgrep
не поддерживает его, скажите, чтобы он также просматривал/dev/null
. Это не изменит вывод, но, посколькуgrep
ему дается несколько файлов, он всегда печатает имя файла для каждого попадания:источник
tac
. Он выйдет, как только будет найдено первое совпадение. Я только что протестировал текстовый файл 832M и шаблон, найденный в последней строке.grep -m 1 pattern file
инструмент ~ 7 секунд иtac file | grep -m1 pattern
взял0.009
.... будет работать, если у вас есть GNU,
sed
который поддерживает-s
опцию eparate files и POSIXfind
.Вы, вероятно, должны добавить квалификаторы
! -type d
или-type f
, хотя, потому что попытка чтения каталога не будет очень полезной, и дальнейшее сужение диапазона до обычных файлов может избежать зависания чтения в канальном или последовательном файле устройства.Логика невероятно проста -
sed
перезаписывает своеh
старое пространство копией любой входной строки, которая совпадаетsearchstring
, а затемd
отключает все выходные строки, кроме последней, для каждого входного файла. Когда он добирается до последней строки, онx
меняет свое пространство удержания и шаблонные пространства, и поэтому, если он вообщеsearchstring
был найден во время чтения файла, последнее такое вхождение будет автоматически напечатано для вывода, в противном случае он записывает пустую строку. (добавьте/./!d
в конецsed
скрипта, если это нежелательно) .Это будет делать один
sed
вызов для некоторых входных файлов 65k - или независимо от вашегоARG_MAX
предела. Это должно быть очень эффективным решением, и оно довольно просто реализуется.Если вам также нужны имена файлов, учитывая недавний GNU,
sed
вы можете записать их в отдельные строки с помощьюF
команды, или вы можете распечатать ихfind
в отдельном списке для пакета, добавив-print
основной после+
.источник
Как насчет:
Вышеприведенное дает хороший вывод с последним вхождением строки поиска в каждом файле, за которым следует соответствующее имя файла после запятой (измените часть ", $ 1" в echo, чтобы изменить форматирование, или удалите его, если в этом нет необходимости). Пример вывода, который ищет строку поиска «10» в файлах с префиксом «file», выглядит следующим образом:
источник
Это использует GNU
grep
«s-H
и-n
опции всегда печатать как имя файла и LINENUMBER всех матчей, то он сортирует по имени файла и LINENUMBER, и трубы ее в AWK, который хранит последний матч для каждого файла в массив, и в конце концов печать Это.Довольно грубый метод, но он работает.
источник