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


L'une de mes commandes BASH préférées est:

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

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

En raison de mon projet actuel et de la structure de mon code, je souhaiterais que cette commande BASH soit encore plus avancée en ne recherchant aucun fichier se trouvant dans ou sous un répertoire contenant ".svn", ni aucun fichier se terminer par ".html"

La page MAN pour trouver m'a un peu confondu cependant. J'ai essayé d'utiliser -prune, et cela m'a donné un comportement étrange. Pour tenter 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


110
2018-03-05 23:28


origine


Juste FYI: find n'est pas une commande intégrée mais un programme distinct - WakiMiko
Vous pouvez rechercher dans le fichier avec grep -rl 'SearchString' - emanuele
@emanuele Bonjour, bienvenue sur SuperUser (et sur le réseau Stack Exchange). C'est une question que j'ai posée et à laquelle j'ai répondu il y a deux ans et demi. En règle générale, si vous souhaitez ajouter une réponse à la question, veuillez le faire en défilant vers le bas et en y répondant plutôt que dans un commentaire. Comme cette question a déjà une réponse acceptée (celle avec la coche verte), il est peu probable que votre réponse suscite beaucoup d'attention. FYI. - Cody S
Bonjour, ce n'est pas une réponse à votre question. Ce n’est qu’un conseil, comme vous l’avez indiqué dans le préambule, qui utilise find pour rechercher dans un fichier. - emanuele
FWIW, -name '*.*' ne trouve pas tout fichiers: seulement ceux avec un . en leur nom (l'utilisation de *.* est typiquement un DOS-ism, alors que dans Unix, vous utilisez normalement juste * pour ça). Pour vraiment les faire tous, il suffit de supprimer l'argument: find . -exec .... Ou si vous voulez seulement appliquer grep aux fichiers (et ignorer les répertoires) alors faites find . -type f -exec .... - Stefan


Réponses:


Vous pouvez utiliser la fonctionnalité negate (!) De find pour ne pas faire correspondre les fichiers avec 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 donc exec ne sera pas exécuté.


157
2018-03-06 00:40



Dois-je toujours spécifier -name '.'quelque part là-bas? Est-ce que je ferais ça avant ou après les négations? - Cody S
L'intention de votre *.* match pour s'assurer que seuls les fichiers contenant un .? Find trouvera tous les fichiers en l’absence de name directive, le ci-dessus correspondra à tout sauf html et svn - Paul
Je pense que tu veux -wholename '*.svn*' plutôt que -name. - fuenfundachtzig
Oui, pour que le .svn les répertoires sont exclus des résultats de la recherche. - fuenfundachtzig
@Noumenon ! -name '.' devrait exclure . à partir des résultats de la recherche. - Paul


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

  • ack-grep est une sorte de "développeur" grep" lequel par défaut ignore les répertoires de contrôle de version et les fichiers temporaires. le man page explique comment rechercher uniquement les types de fichiers spécifiques et comment définir votre propre.
  • grepest propre --exclude et --exclude-dir les options peuvent être utilisées très facilement pour sauter un fichier globs et unique répertoires (pas de regroupement pour les répertoires, malheureusement).
  • 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.

9
2018-03-06 13:54





Le suivant find commande rase les répertoires dont les noms contenir  .svn, Bien qu'il ne descende pas dans le répertoire, le nom du chemin élagué est imprimé ... (-name '*.svn' est la cause!) ..

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

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

La méthode suivante utilise xargs au lieu de -exec, et suppose qu'il n'y a pas de nouvelles lignes \n dans n'importe lequel de vos fichiers des noms. Comme utilisé ici, xargs est très semblable à trouver \+.

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

Cela exclut les répertoires dont les noms contenir  .svn et greps uniquement les fichiers qui ne se terminent pas par .html.

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

7
2018-03-06 03:29



Merci de signaler le \+ variante de l'action -exec. Hourra pour de légers problèmes de côté! - Christian Long
Bien sûr, depuis + n'est pas un caractère spécial au shell, vous n'avez pas besoin de taper \ avant cela. - Scott