web-dev-qa-db-fra.com

Comment est-ce que je grep récursivement à travers les fichiers .gz?

J'utilise un script pour télécharger régulièrement mes messages gmail qui compresse le .eml brut dans des fichiers .gz. Le script crée un dossier pour chaque jour, puis compresse chaque message dans son propre fichier.

Je voudrais un moyen de rechercher dans cette archive une "chaîne".

Grep seul ne semble pas le faire. J'ai également essayé SearchMonkey.

144
Kendor

Si vous voulez grep récursivement dans tous les fichiers .eml.gz du répertoire courant, vous pouvez utiliser:

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

Vous devez échapper au premier * pour que le Shell ne l'interprète pas. -print0 indique à find d'imprimer un caractère nul après chaque fichier trouvé; xargs -0 lit à partir de l'entrée standard et exécute la commande après pour chaque fichier; zgrep fonctionne comme grep, mais décompresse d'abord le fichier.

153
J. K. Stafford

Il y a beaucoup de confusion ici car il n'y a pas qu'un seul zgrep. J'ai deux versions sur mon système, zgrep de gzip et zgrep de zutils . Le premier n'est qu'un script wrapper qui appelle gzip -cdfq. Il ne prend pas en charge le -r, --recursive commutateur.1
Ce dernier est un c++ programme et prend en charge le -r, --recursive option.
Fonctionnement zgrep --version | head -n 1 révélera lequel (le cas échéant) d'entre eux est la valeur par défaut:

zgrep (gzip) 1.6

est le script wrapper,

zgrep (zutils) 1.3

est l'exécutable cpp.
Si vous avez ce dernier, vous pouvez exécuter:

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

Quoi qu'il en soit, comme suggéré, find + zgrep fonctionnera aussi bien avec l'une ou l'autre version de zgrep:

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

Si zgrep est absent de votre système (très peu probable), vous pouvez essayer avec:

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

mais il y a un inconvénient majeur: vous ne saurez pas où sont les correspondances car il n'y a pas de nom de fichier ajouté aux lignes correspondantes.


1: car ce serait problématique

70
don_crissti

ag est une variante de grep, avec quelques fonctionnalités supplémentaires Nice.

  • a l'option -z pour les fichiers compressés,
  • a de nombreuses fonctionnalités d'ack.
  • c'est rapide

Donc:

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

S'il n'est pas installé,

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

La récursivité seule est facile:

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

Cependant, pour les fichiers compressés, vous avez besoin de quelque chose comme:

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

path/to/directory doit être le répertoire parent contenant les sous-répertoires de chaque jour.


zgrep est la réponse évidente mais, malheureusement, il ne prend pas en charge le -r drapeau. De man zgrep:

Ces options grep entraîneront la fin de zgrep avec un code d'erreur: (- [d rR zZ] | --di * | --exc * | --inc * | --rec * | - nu *).

5
terdon

Si votre système a zgrep, vous pouvez simplement

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

Si votre système n'a pas zgrep, vous pouvez utiliser la commande find pour exécuter zcat et grep sur chaque fichier comme ceci:

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

3

xzgrep -l "chaîne" ./*/*.eml.gz

xzgrep est un dérivé des utilitaires zgrep (moins/bin/xzgrep)

Depuis la page Man:

xzgrep appelle grep (1) sur des fichiers qui peuvent être non compressés ou compressés avec xz (1), lzma (1), gzip (1), bzip2 (1) ou lzop (1). Toutes les options spécifiées sont transmises directement à grep (1).

-l affiche le nom du fichier correspondant

-R pour la récursivité ne fonctionnera pas car il est spécifiquement interdit dans le script, mais un simple globbing Shell devrait nous y amener

./*/*.eml.gz

à partir d'un chemin relatif où ./today/sample.eml.gz, correspond à toutes les instances qui sont un niveau en dessous de notre position relative dans le shell, qui se termine par ".eml.gz"

0
John