web-dev-qa-db-fra.com

fichiers Grep de la liste

J'essaie d'exécuter Grep contre une liste de quelques centaines de fichiers:

$ head -n 3 <(cat files.txt)
admin.php
ajax/accept.php
ajax/add_note.php

Cependant, même si je suis grepping pour une chaîne que je connaisse se trouve dans les fichiers, vous ne recherchez pas les fichiers:

$ grep -i 'foo' <(cat files.txt)

$ grep -i 'foo' admin.php
The foo was found

Je connais le drapeau -f qui lira les modèles à partir d'un fichier. Mais comment lire les fichiers d'entrée ?

J'avais considéré l'horrible solution de contournement de copier les fichiers à un répertoire temporaire comme cp semble prendre en charge le format <(cat files.txt), et de là grepping les fichiers. Shirley il y a une meilleure façon.

15
dotancohen

Vous semblez être grepping la liste des noms de fichiers, pas les fichiers eux-mêmes. <(cat files.txt) vise simplement les fichiers. Essayer <(cat $(cat files.txt)) pour les concaténer et les rechercher comme un seul flux, ou

grep -i 'foo' $(cat files.txt)

donner à Grep tous les fichiers.

Cependant, s'il y a trop de fichiers sur la liste, vous pouvez avoir des problèmes de nombre d'arguments. Dans ce cas, j'écrirais juste

while read filename; do grep -Hi 'foo' "$filename"; done < files.txt
22
orion
xargs grep -i -- foo /dev/null < files.txt

en supposant que les fichiers soient vides ou transversaux délimités (où des citations ou des backslashes peuvent être utilisés pour échapper à ces séparateurs). Avec GNU xargs Vous pouvez spécifier le délimiteur avec -d (qui désactive ensuite la manipulation de la citation).

(unset -v IFS; set -f; grep -i -- foo $(cat files.txt))

en supposant que les fichiers soient de l'espace, de l'onglet ou de la nouvelle ligne séparés (aucun moyen de vous échapper, vous pouvez choisir un séparateur différent en l'attribuant à IFS). Celui-ci échouera si la liste des fichiers est trop grosse sur la plupart des systèmes.

Ceux-ci supposent également qu'aucun des fichiers n'est appelé -.

8
Stéphane Chazelas

Pour lire une liste de noms de fichiers de stdin, vous pouvez utiliser xargs. Par exemple.,

cat files.txt | xargs -d'\n' grep -i -- 'foo'

Par défaut, xargs lit les éléments de l'entrée standard, délimité par des blancs. Les -d'\n' Dites-lui d'utiliser Newline comme argument Délimiteur, il peut donc gérer les noms de fichiers contenant des blancs. (Comme le souligne Stéphane Chazelas, c'est un GNU Extension). Cependant, il ne contenir pas de noms de fichiers contenant de nouvelles lignes; nous aurions besoin d'une approche légèrement plus compliquée pour gérer ceux-ci.

FWIW, cette approche est un peu plus rapide qu'une while read boucle, comme la commande Bash's read est très lente - elle lit son caractère de données par caractère, alors que xargs lit son entrée plus efficacement. En outre, xargs invoque uniquement la commande grep autant de fois que nécessaire, avec chaque invocation recevant plusieurs noms de fichiers, et plus efficace que d'appeler grep individuellement pour chaque fichier Nom.

Voir la page Page Xargs Man et la page Info Xargs pour plus de détails.

7
PM 2Ring

xargs peut lire des éléments d'un fichier (comme votre files.txt liste) avec son option:

   --arg-file=file
   -a file
          Read items from file instead of standard input.  If you use this
          option, stdin remains unchanged when commands are  run.   Other‐
          wise, stdin is redirected from /dev/null.

Cela devrait donc fonctionner aussi:

xargs -a files.txt grep -i 'foo'

ou pour les espaces dans les noms de fichiers

xargs -d'\n' -a files.txt grep -i 'foo'
xargs -I{} -a files.txt grep -i 'foo' {}
3
Xen2050

Vous pouvez également faire un exemple d'un orion, mais est le plus simple:

for i in $(cat files.txt); do grep -i 'foo' $i ; done

(Pour chaque fichier répertorié dans les fichiers.txt exécutez la commande Grep dessus.)

1
Michael