Como faço grep recursivamente através de arquivos .gz?

117

Estou usando um script para baixar regularmente as mensagens do meu Gmail que comprime o .eml cru em arquivos .gz. O script cria uma pasta para cada dia e, em seguida, compacta cada mensagem em seu próprio arquivo.

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

O Grep sozinho não parece fazer isso. Eu também tentei o SearchMonkey.

    
por Kendor 02.03.2015 / 17:03

6 respostas

123

Se você quiser 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 informa ao find para imprimir um caractere nulo após cada arquivo que encontrar; xargs -0 lê a entrada padrão e executa o comando depois dela para cada arquivo; zgrep funciona como grep , mas descompacta o arquivo primeiro.

    
por 02.03.2015 / 17:20
55

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 interruptor -r, --recursive . 1
Este último é um programa c++ e suporta a opção -r, --recursive .
A execução de 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 este último, você pode 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 do 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

    
por 03.03.2015 / 11:18
6

ag é uma variante de grep , com alguns recursos extras interessantes.

  • tem a opção -z para arquivos compactados,
  • tem muitos recursos do ack.
  • é rápido

Então:

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)
    
por 03.03.2015 / 00:43
4

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 sinalizador -r . De man zgrep :

These grep options will cause zgrep to terminate with an error code: (-[drRzZ]|--di*|--exc*|--inc*|--rec*|--nu*).

    
por 02.03.2015 / 17:14
3

Se o seu sistema tiver 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 ' \;

    
por 02.03.2015 / 17:22
0

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

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

Na página "Man":

xzgrep invokes grep(1) on files which may be either uncompressed or compressed with xz(1), lzma(1), gzip(1), bzip2(1), or lzop(1). All options specified are passed directly to grep(1).

-l imprime o nome do arquivo correspondente

-R para recursão não funcionará, pois é especificamente proibido no script, no entanto, a simples globalização de conchas deve nos levar até lá

./*/*.eml.gz

de um caminho relativo em que ./today/sample.eml.gz, correspondência em todas as instâncias do que são um nível abaixo da nossa posição relativa no shell, que termina com ".eml.gz"

    
por 13.11.2017 / 19:33