desenv-web-rp.com

Como grep recursivamente através de arquivos .gz?

Estou usando um script para baixar regularmente minhas mensagens do Gmail que compactam o arquivo .eml bruto em arquivos .gz. O script cria uma pasta para cada dia e compacta todas as mensagens em seu próprio arquivo.

Eu gostaria de uma maneira de pesquisar neste arquivo por uma "string".

Grep sozinho não parece fazê-lo. Eu também tentei o SearchMonkey.

144
Kendor

Se você deseja grep recursivamente em todos os arquivos .eml.gz no diretório atual, você pode usar:

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

Você tem que escapar do primeiro * para que o Shell não o interprete. -print0 diz ao find para imprimir um caractere nulo após cada arquivo encontrado; xargs -0 lê da entrada padrão e executa o comando após cada arquivo; zgrep funciona como grep, mas descompacta o arquivo primeiro.

153
J. K. Stafford

Há muita confusão aqui porque não há apenas um zgrep. Eu tenho duas versões no meu sistema, zgrep de gzip e zgrep de zutils . O primeiro é apenas um script de wrapper que chama gzip -cdfq. Não suporta o -r, --recursive interruptor.1 1
O último é um c++ programa e suporta o -r, --recursive opção.
Corrida zgrep --version | head -n 1 revelará qual deles (se houver) é o padrão:

zgrep (gzip) 1.6

é o script do wrapper,

zgrep (zutils) 1.3

é o executável cpp.
Se você tiver o último, poderá executar:

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

De qualquer forma, como sugerido, find + zgrep funcionará igualmente bem com qualquer versão de zgrep:

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

Se zgrep estiver ausente no seu sistema (altamente improvável), você pode tentar:

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

mas há uma grande desvantagem: você não saberá onde estão as correspondências, pois não há um nome de arquivo anexado às linhas correspondentes.


1: porque seria problemático

70
don_crissti

ag é uma variante de grep, com alguns recursos extras agradáveis.

  • possui a opção -z para arquivos compactados,
  • tem muitos recursos de reconhecimento.
  • isso é rápido

Assim:

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

Se não estiver instalado,

apt-get install silversearcher-ag   (debian and friends)
yum install the_silver_searcher     (Fedora)
brew install the_silver_searcher    (mac)
9
JJoao

A recursão sozinha é fácil:

   -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.

No entanto, para arquivos compactados, você precisa de algo como:

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

path/to/directory deve ser o diretório pai que contém os subdiretórios para cada dia.


zgrep é a resposta óbvia, mas, infelizmente, não suporta o -r sinalizador. De man zgrep:

Essas opções de grep farão com que o zgrep termine com um código de erro: (- [d rR zZ] | --di * | --exc * | --inc * | --rec * | - nu *).

5
terdon

Se o seu sistema possui o zgrep, você pode simplesmente

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

Se o seu sistema não possui zgrep, você pode usar o comando find para executar o zcat e o grep em cada arquivo da seguinte forma:

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

3
Nate from Kalamazoo

xzgrep -l "string" ./*/*.eml.gz

xzgrep é um derivado dos utilitários do zgrep (menos/bin/xzgrep)

Na página Man:

o xzgrep chama grep (1) em arquivos que podem ser descompactados ou compactados com xz (1), lzma (1), gzip (1), bzip2 (1) ou lzop (1). Todas as opções especificadas são passadas diretamente para grep (1).

-l imprime o nome do arquivo correspondente

-R para recursão não funcionará, pois é especificamente proibido no script, no entanto, simples globbing do Shell deve nos levar até lá

./*/*.eml.gz

a partir de um caminho relativo em que ./today/sample.eml.gz, corresponda em todas as instâncias desse nível, um nível abaixo da nossa posição relativa no Shell, que termina com ".eml.gz"

0
John