web-dev-qa-db-fra.com

Comment ignorer certains noms de fichiers en utilisant "find"?

Une de mes commandes BASH préférées est:

find . -name '*.*' -exec grep 'SearchString' {} /dev/null \;

qui recherche le contenu spécifié de SearchString dans le contenu de tous les fichiers situés dans et sous le répertoire en cours. En tant que développeur, cela s’est parfois révélé utile.

Cependant, en raison de mon projet actuel et de la structure de ma base de code, j'aimerais rendre cette commande BASH encore plus évoluée en ne recherchant aucun fichier se trouvant dans ou sous un répertoire contenant ".svn", ni aucun fichier contenant un fichier. se termine par ".html"

La page MAN for find m'a un peu déroutée. J'ai essayé d'utiliser -Prune, et cela m'a donné un comportement étrange. En essayant de ne sauter que les pages .html (pour commencer), j'ai essayé:

find . -wholename './*.html' -Prune -exec grep 'SearchString' {} /dev/null \;

et n'a pas eu le comportement que j'espérais. Je pense que je pourrais manquer le point de -Prune. Pourriez-vous m'aider?

Merci

128
Cody S

Vous pouvez utiliser la fonction negate (!) De find pour ne pas faire correspondre les fichiers portant des noms spécifiques:

find . ! -name '*.html' ! -path '*.svn*' -exec grep 'SearchString' {} /dev/null \;

Donc, si le nom se termine par .html ou contient .svn n'importe où dans le chemin, il ne correspondra pas et l'exécution ne sera donc pas exécutée.

179
Paul

J'ai le même problème depuis longtemps et plusieurs solutions peuvent être appliquées dans différentes situations:

  • ack-grepest une sorte de "développeur grepname__" qui par défaut ignore les répertoires de contrôle de version et les fichiers temporaires. La page manexplique comment effectuer une recherche dans des types de fichiers spécifiques et comment définir votre propre .
  • grepname Les options propres --exclude et --exclude-dir de __ peuvent être utilisées très facilement pour ignorer les répertoires file globs et single _ (malheureusement, aucune annotation globale pour les répertoires).
  • find . \( -type d -name '.svn' -o -type f -name '*.html' \) -Prune -o -print0 | xargs -0 grep ... devrait fonctionner, mais les options ci-dessus sont probablement moins compliquées à long terme.
10
l0b0

La commande find suivante effectue le nettoyage des répertoires dont les noms contiennent .svn. Bien qu’il ne descende pas dans le répertoire, le nom du chemin élagué est imprimé ... (-name '*.svn' en est la cause!) ..

Vous pouvez filtrer les noms de répertoire via: grep -d skip qui ignore silencieusement ces "noms de répertoire" en entrée.

Avec GNU grep, vous pouvez utiliser -H au lieu de /dev/null. Un problème mineur: \+ peut être beaucoup plus rapide que \;, par exemple. pour 1 million de fichiers d'une ligne, en utilisant \; il a fallu 4m20s , en utilisant \+ il n'a fallu que 1.2s .

La méthode suivante utilise xargs au lieu de -exec et suppose qu'il n'y a pas de saut de ligne \n dans aucun de vos fichiers-noms . Telle qu'elle est utilisée ici, xargs est pratiquement identique à \+ de find.

xargs peut transmettre des noms de fichiers contenant des espaces consécutifs en modifiant le délimiteur d'entrée en '\n' avec l'option -d.

Ceci exclut les répertoires dont les noms contiennent .svn et ne traite que les fichiers ne se terminant pas par .html.

find . \( -name '*.svn*' -Prune  -o ! -name '*.html' \) |
   xargs -d '\n' grep -Hd skip 'SearchString'
7
Peter.O