Comment passer une liste de fichiers à grep

98

J'utilise findet je reçois une liste de fichiers que je veux grepparcourir. Comment puis-je diriger cette liste vers grep?

Arcabard
la source

Réponses:

116

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

$ find … | xargs grep 'search'

Ou pour incorporer la commande dans votre grepligne avec des backticks ou $(), qui exécutera la commande et substituera 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 findla capacité à exécuter un programme sur les arguments donnés, cela est intégré:

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

Tout entre -execet ;est la commande à exécuter; {}est remplacé par le nom de fichier trouvé par find. Cela va exécuter un grepfichier séparé pour chaque fichier; car greppeut prendre plusieurs noms de fichiers et les rechercher tous, vous pouvez changer le mot ;to +pour indiquer find afin de transmettre tous les noms de fichiers correspondants grepà la fois:

$ find … -exec grep 'search' {} \+
Michael Mrozek
la source
1
Il convient de noter que les deux premiers formulaires ne fonctionnent pas avec les noms de fichiers contenant des espaces.
enzotib
1
Je préfère find ... -type f -print0 | xargs -r0 grep 'search' /dev/null. QED. Bien que -exec +très efficace, il n’existe pas sur toutes les versions de find.
Arcege
Malheureusement, je ne peux pas vérifier correctement 3 fois.
Arcabard
3
Je suggère d'utiliser le -exec, plutôt que le xargs. Si vous utilisez -execin find, il ne créera qu'un seul shell à grep pour le contenu. Si vous utilisez le xargs, cela créera deux coquilles: une pour le findet l'autre pour le xargs.
2
expérimentalement, je trouve que la $ find … -exec grep 'search' {} \+forme est beaucoup plus rapide.
Gogoud
9

Certaines versions de grep(par exemple, sur Linux non intégré, BSD ou Mac OS X) ont une -roption permettant d'effectuer une recherche récursive. Sous OpenBSD, utilisez -R(et il n'y en a pas --excludecomme dans l'exemple ci-dessous). Cela couvre des combinaisons simples de findavec grep.

Si votre implémentation ne possède pas l' -Rindicateur ou si vous souhaitez des critères de correspondance de fichiers plus élaborés, vous pouvez utiliser le -execprincipal de findpour l'exécuter grep. Quelques findimplémentations plus anciennes ne supportent pas -exec+; sur ces systèmes, utilisez a ;au lieu de la +(ceci appelle grepune fois par fichier, donc ce sera plus lent, mais sinon le résultat sera le même). Notez l' /dev/nullastuce pour que greple nom de fichier soit affiché même s'il est appelé sur un seul fichier (GNU grep et FreeBSD / NetBSD / OSX grep ont la -Hpossibilité d'obtenir le même effet).

find . -type f -name '*.o' -prune -o -exec grep 'needle' /dev/null {} +
grep -r --exclude='*.o' 'needle' .
Gilles
la source
2
GNU grepa l' -Hoption de toujours imprimer le nom de fichier.
enzotib