Як переглядати рекурсивно через файли .gz?


135

Я використовую сценарій, щоб регулярно завантажувати свої gmail-повідомлення, які стискають сировину .eml у файли .gz. Сценарій створює папку на кожен день, а потім стискає кожне повідомлення у свій власний файл.

Я хотів би спосіб пошуку в цьому архіві "рядка".

Сам Греп, здається, не робить цього. Я також спробував SearchMonkey.


16
використання zgrep:zgrep - search possibly compressed files for a regular expression
Аркадіуш Драбчик

Відповіді:


141

Якщо ви хочете рекурсивно виконувати всі файли .eml.gz у поточному каталозі, ви можете використовувати:

find . -name \*.eml.gz -print0 | xargs -0 zgrep "STRING"

Ви повинні уникнути першого, *щоб оболонка не інтерпретувала його. -print0повідомляє find для друку нульового символу після кожного знайденого файла; xargs -0читає зі стандартного вводу та виконує команду після нього для кожного файлу; zgrepпрацює як grep, але спочатку розпаковує файл.


2
'-print0' і '-0' не є обов'язковими. xargs використовує "\ n" за замовчуванням.
Хайме М.

1
Вони необхідні, якщо в шляхах можуть бути символи пробілу; немає жодної причини, крім складності, не використовувати їх.
Даніель Гріском

2
zgrepнасправді здається швидше, ніж grepпрацювати на нестиснених файлах. Це повинно бути через те, що стислі файли можна зчитувати з HD та розпаковувати швидше, ніж читання нестисненого файлу з HD.
Геремія

@JaimeM. за замовчуванням xargsвикористовує пробіли (пробіли). Звичайно, файли майже ніколи не містять нових рядків у них, але пробіли не є нечуваними (навіть якщо на них нахмуриться більшість типів UNIXy). Однак, ви можете спростити, не турбуючись про пробіл, ще простіше: find . -name '*.eml.gz' -exec zgrep "STRING" {} +це отримує стільки ж аргументів за запуск xargs, безпеку -print0/ -0та все без накладних витрат на додатковий процес запуску та трубопроводу, і досить стисло. -execз +вказано POSIX, тому він повинен бути на більшості напівсвітніх UNIX-подібних систем, наскільки мені відомо.
ShadowRanger

@Jred Чи існує спосіб пошуку підстановки лише знаючи початок шаблону файлу? Наприклад, у мене є .gz файли, які мають кінці дати / часу в кінці. ABCLog04_18_18_2_21.gz Чи є спосіб рекурсивно шукати файли, що починаються з ABC *. Я спробував замінити \*.eml.gzу вашому прикладі вище ABCLog*та отримати помилку щодо формату файлу .:find: paths must precede expression: ABCLog-2018-03-12-10-16-1.log.gz Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
DevelopingDeveloper

68

Тут багато плутанини, тому що існує не одна zgrep. У мене в системі дві версії, zgrepз gzipі zgrepз zutils. Перший - це лише сценарій обгортки, який дзвонить gzip -cdfq. Він не підтримує -r, --recursiveкомутатор. 1
Остання являє собою c++програму , і вона підтримує в -r, --recursiveопції.
Запуск zgrep --version | head -n 1виявить, який з них (за наявності) є типовим:

zgrep (gzip) 1.6

це сценарій обгортки,

zgrep (zutils) 1.3

є cppвиконуваним файлом.
Якщо у вас є останні, ви можете запустити:

zgrep 'pattern' -r --format=gz /path/to/dir

У будь-якому випадку, як було запропоновано, find+ zgrepбуде однаково добре працювати з будь-якою з версій zgrep:

find /path/to/dir -name '*.gz' -exec zgrep -- 'pattern' {} +

Якщо zgrepвідсутня у вашій системі (дуже малоймовірно), ви можете спробувати:

find /path/to/dir -name '*.gz' -exec sh -c 'gzip -cd "$0" | grep -- "pattern"' {} \;

але є головний мінус: ви не знатимете, де збігаються, оскільки ім'я файлу не призначається для відповідних рядків.


1: тому що це було б проблематично


1
якщо zgrepз zutils недоступний, ви можете встановити його в Ubuntu за допомогою sudo apt-get install zutils.
therealmarv

1
Продовження від @therealmarv ... і тоді Ubuntu використовуватиме zutils zgrep замість gzip. Тоді -r працює!
Ілля Лінн

Чи є спосіб надрукувати номер рядка файлу, на якому узгоджений шаблон?
DogEatDog

@DogEatDog - так само grep -n, zgrep -nбуде друкувати рядок no.s. Це в посібнику ...
don_crissti

7

agє варіантом grep, з деякими приємними додатковими можливостями.

  • має -z варіант для стислих файлів,
  • має багато функцій ack.
  • це швидко

Тому:

ag -r -z your-pattern-goes-here   folder

Якщо не встановлено,

apt-get install silversearcher-ag   (debian and friends)
yum install the_silver_searcher     (fedora)
brew install the_silver_searcher    (mac)

1
Я отримую ag: truncated file: Successяк результат. Будь-який інший прапор слід додати?
Яр

4

Сама рекурсія проста:

   -r, --recursive
          Read all files  under  each  directory,  recursively,  following
          symbolic  links  only  if they are on the command line.  This is
          equivalent to the -d recurse option.

   -R, --dereference-recursive
          Read all files under each directory,  recursively.   Follow  all
          symbolic links, unlike -r.

Однак для стислих файлів вам потрібно щось на зразок:

shopt globstar 
for file in /path/to/directory/**/*gz; do zcat ""$file" | grep pattern; done

path/to/directory має бути батьківським каталогом, який містить підкаталоги на кожен день.


zgrepце очевидна відповідь, але, на жаль, він не підтримує -rпрапор. Від man zgrep:

Ці параметри grep призведуть до припинення згрепу кодом помилки: (- [d rR zZ] | --di * | --exc * | --inc * | --rec * | --nu *).


3

Якщо у вашій системі є zgrep, ви можете просто

zgrep -irs your-pattern-goes-here the-folder-to-search-goes-here/

Якщо у вашій системі немає zgrep, ви можете скористатися командою find, щоб запустити zcat та grep проти кожного файлу так:

find the-folder-to-search-goes-here/ -name '*.gz' \ -exec sh -c 'echo "Searching {}" ; zcat "{}" | grep your-pattern-goes-here ' \;


Пробачте мені зеленість з цього приводу ... файли, які слід шукати, на кілька шарів глибиною. ~ / gmvault-db / db / 2015-02 містить папку для кожного архівованого місяця, а потім під нею зберігаються .gz файли за цей місяць. Якщо я шукаю .mil у цілому дереві, це я б робив? find ~ / gmvault-db / db / -name '* .gz' \ -exec sh -c 'echo "Пошук {}"; zcat "{}" | grep .mil '\;
Кендор

1
Це добре - in -irs "r" призведе до регресивного пошуку zgrep. Команда find працює рекурсивно за замовчуванням, тому будь-який файл, який закінчується в .gz, буде zcatted і перейде в grep. (і {} буде розширено до відносного шляху файлу, який збирається шукати). Тож коли ви отримаєте хіт, йому передуватиме Searching ~/gmvault-db/db/2015-02/03/whatever.gz
Нейт з Каламазу

Ось що я повертаю: find: "Шляхи повинні передувати виразу: -exec" Ось команда, яку я використав: find ~ / gmvault-db / db / -name '* .gz' \ -exec sh -c 'echo "Пошук { } "; zcat "{}" | grep .mil '\;
Кендор

вийміть зворотну косу рису між '* .gz' та -exec.
Нейт з Каламазу

4
zgrepне візьме -rпрапор чомусь. Це згадка в man zgrep(також дивіться мою відповідь).
тердон

0

xzgrep -l "рядок" ./*/*.eml.gz

xzgrep - похідне від утиліти zgrep (менше / bin / xzgrep)

На сторінці Man:

xzgrep викликає grep (1) у файлах, які можуть бути або нестисненими, або стисненими за допомогою xz (1), lzma (1), gzip (1), bzip2 (1) або lzop (1). Усі вказані параметри передаються безпосередньо grep (1).

-друкую відповідне ім'я файлу

-R для рекурсії не буде працювати, оскільки це спеціально заборонено в сценарії, однак просте поглинання оболонки повинно нас туди дістати

./*/*.eml.gz

від відносного шляху, де ./today/sample.eml.gz збігаються на всіх примірниках, які на один рівень нижче нашого відносного положення в оболонці, що закінчується на ".eml.gz"

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.