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.
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
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é -
.
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.
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' {}
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.)