Хронологически файлы grep или zgrep в папке в зависимости от расширения файла (xargs)

0

У меня есть десятки папок, которые содержат как простые текстовые файлы журнала, так и сжатые старые журналы. Моя цель - запустить только один вкладыш (по одной папке за раз), чтобы получить все результаты grep в соответствии с порядком отметок времени, независимо от того, является ли файл журнала, содержащий совпадение, txt или gz, и, если возможно, оптимизировать производительность.

Это прекрасно работает для простых файлов:

ls -rt log.*.txt | xargs grep <treasure> -

Я использую это, а не просто grep, поэтому результаты сортируются в хронологическом порядке создания файла, возможно, в течение нескольких дней, а не сортируются по имени файла. Имена файлов (log. #. Txt) растут до определенного целочисленного предела, затем переносятся в log.0.txt, но это может пересекать 24-часовую отметку или нет.

После переноса txt-файлов старые файлы распаковываются: log. #. Archive.gz. Сохраняются только файлы gz с целочисленным ограничением.

Я думал использовать оператор if / fi для grep или zgrep в зависимости от расширения текущего файла. Однако, мой первый шаг, чтобы попробовать это только на файлах gz, не работал:

ls -rt log.*.gz | xargs zgrep <treasure> -

Я получаю кучу ошибок "файл 'сокровище' не найден" (по одной на каждый файл .gz)

Я также пытался

ls -rt "log.*.gz" | xargs -0 zgrep <treasure> -

к тому же результату. Я знал, что это должно быть из-за моего элементарного понимания команды xargs. Может быть, я даже смогу сделать это с помощью соответствующих опций grep / zgrep, find или чего-то еще полностью.

user2632063
источник
Есть ли в <сокровище> пробелы или специальные символы?
Давидго
В моей версии zgrep вы получите тот же вывод, что и для grep, если вы дадите ему обычный файл вместо .gz, так что, возможно, вы можете просто использовать его по умолчанию. From man zgrep: "В противном случае данные файлы при необходимости распаковываются и передаются в grep." (выделено мое)
WAF

Ответы:

0

Вот несколько вещей не так:

  • Старайтесь не перебирать или передавать результаты, полученные lsв другом инструменте. Он сломается, если файлы содержат пробелы или символы новой строки, в зависимости от того, как составлена ​​команда. В вашем случае, однако, нет простого способа выполнить то, что вы хотите, кроме как использовать ls. Так что, если вы знаете, что имена ваших файлов не будут содержать символ новой строки, тогда вы в порядке.

  • <treasure> -будет интерпретироваться оболочкой как перенаправление. Первая скобка <будет читаться оболочкой, что означает «читать STDIN из файла с именем treasure». Второе значение в скобках читается как > -«запись STDOUT в файл с именем -». Таким образом, вы должны правильно цитировать шаблон , который вы пытаетесь прочитать: grep "<treasure>".

  • -0Опция xargsсчитывает входные данные как ASCII , NUL-разделители строк, которые lsне будут производить. Это полезно только в сочетании с инструментами, которые могут создавать выходные данные, разделенные NUL, например, findс помощью -print0опции.

  • Я не понимаю цели -ваших команд.

Итак, попробуйте что-то вроде этого:

shopt -s extglob
ls -rt1 +(log.*.txt|log.*.gz) | xargs zgrep "<treasure>"

или же:

ls -rt1 +(log.*.txt|log.*.gz) | xargs -L1 zgrep "<treasure>"

Объяснение:

  • extglob позволяет сопоставить оба расширения файла
  • -1делает lsодин файл в каждой строке
  • +(…|…) означает «один или несколько» шаблона
  • Если вы используете -L1, xargsбудет передавать только один файл за zgrepодин раз. Это может быть не то, что вы хотите, хотя.
slhck
источник
Спасибо, имена файлов - это только буквенно-цифровые символы и точки, шаблон поиска - только буквенно-цифровые символы (должны были быть исключены из скобок), поэтому кажется, что цикл также работает. Но это более компактно и явно, поскольку оно ищет оба расширения.
user2632063
-1

Что о:

for each in `ls -rt log.*.gz`; do zgrep "<TREASURE>" $each; done
davidgo
источник
Это ломается, если имена файлов содержат пробельные символы или символы любого типа.
Slhck