web-dev-qa-db-fra.com

Comment passer une liste de fichiers à grep

J'utilise find et j'obtiens une liste des fichiers que je veux grep. Comment diriger cette liste vers grep?

105
MageProspero

Eh bien, le cas générique qui fonctionne avec n'importe quelle commande qui écrit dans stdout est d'utiliser xargs, qui vous permettra d'attacher n'importe quel nombre d'arguments de ligne de commande à la fin d'une commande:

$ find … | xargs grep 'search'

Ou pour incorporer la commande dans votre ligne grep avec des backticks ou $(), qui exécutera la commande et remplacera sa sortie:

$ grep 'search' $(find …)

Notez que ces commandes ne fonctionnent pas si les noms de fichiers contiennent des espaces ou certains autres "caractères étranges" (\'" Pour xargs, \[*? Pour $(find …)).


Cependant, dans le cas spécifique de find, la possibilité d'exécuter un programme sur les arguments donnés est intégrée:

$ find … -exec grep 'search' {} \;

Tout entre -exec Et ; Est la commande à exécuter; {} Est remplacé par le nom de fichier trouvé par find. Cela exécutera un grep distinct pour chaque fichier; comme grep peut prendre plusieurs noms de fichiers et les rechercher tous, vous pouvez changer le ; en + pour dire à find de passer tous les noms de fichiers correspondants à grep à une fois que:

$ find … -exec grep 'search' {} \+
126
Michael Mrozek

Certaines versions de grep (par exemple sur Linux non intégré ou BSD ou Mac OS X) ont un -r option pour effectuer une recherche récursive. Sur OpenBSD, utilisez -R (et il n'y a pas de --exclude comme dans l'exemple ci-dessous). Cela couvre les combinaisons simples de find avec grep.

Si votre implémentation n'a pas le -R flag, ou si vous voulez des critères de correspondance de fichiers plus sophistiqués, vous pouvez utiliser le -exec primaire de find pour le faire exécuter grep. Quelques anciennes implémentations find ne prennent pas en charge -exec+; sur ces systèmes, utilisez un ; à la place du + (cela appellera grep une fois par fichier, donc ce sera plus lent, mais sinon le résultat sera le même). Noter la /dev/null astuce pour que grep affiche le nom du fichier même s'il se trouve être appelé sur un seul fichier (GNU grep et FreeBSD/NetBSD/OSX grep ont un -H option pour obtenir le même effet).

find . -type f -name '*.o' -Prune -o -exec grep 'needle' /dev/null {} +
grep -r --exclude='*.o' 'needle' .