Почему zgrep не показывает фактические совпадения? - PullRequest
0 голосов
/ 23 октября 2019

Контекст

Допустим, у меня есть два файла a.txt и b.txt с некоторым содержанием ...

$ tail *.txt
==> a.txt <==
ABC
CDE
123
C

==> b.txt <==
C
321
EDC
CBA

Давайте также представим, что файлы теперь помещены вархив gzipped ...

$ tar -czf tarball.tgz *.txt
$ tar -tf tarball.tgz
a.txt
b.txt

Цель

Теперь я хочу просмотреть файлы в архиве. Было бы неплохо увидеть исходное имя файла и номер строки перед совпадением, но мне важнее всего увидеть совпадающие строки.

Что я пробовал?

Сначала я ожидал, чтоzgrep 'pattern' tarball.tgz будет просто работать. Он говорит мне, есть ли совпадение, он может даже подсчитать их, но я не могу найти способ напечатать совпадения ...

$ zgrep 'AB' tarball.tgz
Binary file (standard input) matches
$ zgrep 'C' tarball.tgz
Binary file (standard input) matches
$ zgrep -c 'AB' tarball.tgz
1
$ zgrep -c 'C' tarball.tgz
6

Во-вторых, я подумал, что zcattarball и используйте обычный grep для этого. Но тем не менее, я получаю точно такое же «Двоичный файл (стандартный ввод) соответствует» сообщение ...

$ zcat tarball.tgz | grep 'C'
Binary file (standard input) matches

Я думаю, zcatzgrep) сделать gunzip а нет tar -xf? Если я смотрю на zcat, я вижу тот же вывод, как если бы я только что сделал tar -c ...

$ zcat tarball.tgz
a.txt0000664�3���3���0000000001613554050266013370 0ustar  useruserABC
CDE
123
C
b.txt0000664�3���3���0000000001613554050301013357 0ustar  useruserC
321
EDC
CBA

$ tar -c *.txt
a.txt0000664�3���3���0000000001613554050266013370 0ustar  useruserABC
CDE
123
C
b.txt0000664�3���3���0000000001613554050301013357 0ustar  useruserC
321
EDC
CBA

Итак, наконец, я получил это решение, которое работает нормально:

$ tar -xOzf tarball.tgz | grep 'C'
ABC
CDE
C
C
EDC
CBA

Конечно, если я сейчас спрошу об именах файлов и номерах строк, я не получу ничего полезного ...

$ tar -xOzf tarball.tgz | grep -Hn 'C'
(standard input):1:ABC
(standard input):2:CDE
(standard input):4:C
(standard input):5:C
(standard input):7:EDC
(standard input):8:CBA

Единственный способ, которым я могу придумать, получить результатыЯ хочу, потребовалось бы немного больше сценариев для извлечения архива и запуска grep в цикле ...


Есть ли хороший (простой и лаконичный) способ сделать это?

1 Ответ

0 голосов
/ 23 октября 2019

tar -czf делает две вещи:

  • упаковывает все файлы (в моем примере это только текст) в файл tar (который является двоичным);
  • gzipsэтот tar-файл в gzipped tar-файл.

Как я и подозревал, zgrep или zcat будет делать только gunzip, и останется с файлом tar, который все еще является двоичным. Это объясняет весь вывод, который я получаю.

Простое решение

Самый простой способ - добавить опцию к zgrep:

   -a, --text
          Process a binary file as if it were text; this is equivalent to the --binary-files=text option.

Это будет работатьпочти так же хорошо, как tar -xOzf tarball.tgz | grep -Hn 'C', где мы не получаем отдельные имена файлов, а номера строк находятся по всему выводу tar. Мы также получаем некоторый шум, а именно, формат tar:

$ zgrep -Hna 'C' tarball.tgz
tarball.tgz:1:a.txt0000664�3���3���0000000001613554050266013370 0ustar  jlehuenjlehuenABC
tarball.tgz:2:CDE
tarball.tgz:4:C
tarball.tgz:5:b.txt0000664�3���3���0000000001613554050301013357 0ustar  jlehuenjlehuenC
tarball.tgz:7:EDC
tarball.tgz:8:CBA

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

Лучший вывод

Теперь @Shawn указал мне на этот ответ в Unix StackExchange. Исходя из этого, я мог бы выбрать свой любимый вариант:

$ tar -xf tarball.tgz --to-command='grep -Hn --label="$TAR_ARCHIVE/$TAR_FILENAME" C || true'
tarball.tgz/a.txt:1:ABC
tarball.tgz/a.txt:2:CDE
tarball.tgz/a.txt:4:C
tarball.tgz/b.txt:1:C
tarball.tgz/b.txt:3:EDC
tarball.tgz/b.txt:4:CBA

Я, вероятно, создам себе какую-то функцию для этого, потому что набирать текст неинтересно. Вывод - именно то, что я хотел! :)

...