web-dev-qa-db-fra.com

Commande Unix pour répertorier les fichiers contenant une chaîne mais * NON * contenant une autre chaîne

Comment afficher récursivement une liste de fichiers qui a une chaîne et qui n'en a pas spécifiquement une autre? Je veux aussi évaluer le texte des fichiers, pas les noms de fichiers.


Conclusion:

Selon les commentaires, j'ai fini par utiliser:

find . -name "*.html" -exec grep -lR 'base\-maps' {} \; | xargs grep -L 'base\-maps\-bot'

Cela renvoyait des fichiers avec "base-maps" et non "base-maps-bot". Je vous remercie!!

30
Matrym

Essaye ça:

grep -rl <string-to-match> | xargs grep -L <string-not-to-match>

Explication: grep -lr fait récursivement (r) sortir une liste (l) de tous les fichiers qui contiennent <string-to-match>. xargs boucle sur ces fichiers, appelant grep -L sur chacun d'eux. grep -L affichera le nom du fichier uniquement lorsque le fichier ne contient pas <string-not-to-match>.

42
Sander Marechal

L'utilisation de xargs dans les réponses ci-dessus n'est pas nécessaire; vous pouvez réaliser la même chose comme ceci:

find . -type f -exec grep -q <string-to-match> {} \; -not -exec grep -q <string-not-to-match> {} \; -print

grep -q signifie exécuter silencieusement mais retourner un code de sortie indiquant si une correspondance a été trouvée; find peut ensuite utiliser ce code de sortie pour déterminer s'il faut continuer à exécuter le reste de ses options. Si -exec grep -q <string-to-match> {} \; renvoie 0, puis il exécutera -not -exec grep -q <string-not-to-match>{} \;. Si cela renvoie également 0, il continuera d'exécuter -print, qui imprime le nom du fichier.

Comme une autre réponse l'a noté, l'utilisation de find de cette manière présente des avantages majeurs par rapport à grep -Rl où vous souhaitez uniquement rechercher des fichiers d'un certain type. Si, en revanche, vous voulez vraiment rechercher tous les fichiers, grep -Rl est probablement plus rapide, car il utilise un processus grep pour effectuer le premier filtre pour tous les fichiers, au lieu d'un processus grep distinct pour chaque fichier.

3
Tom

Ces réponses semblent être la correspondance LES DEUX chaînes. La commande suivante devrait mieux fonctionner:

grep -l <string-to-match> * | xargs grep -c <string-not-to-match> | grep '\:0'
1
Chris

Voici une construction plus générique:

find . -name <nameFilter> -print0 | xargs -0 grep -Z -l <patternYes> | xargs -0 grep -L <patternNo>

Cette commande génère des fichiers dont le nom correspond à <nameFilter> (ajustez les prédicats find selon vos besoins) qui contiennent <patternYes>, mais ne contiennent pas <patternNo>.

Les améliorations sont les suivantes:

  • Il fonctionne avec des noms de fichiers contenant des espaces.
  • Il vous permet de filtrer les fichiers par nom.

Si vous n'avez pas besoin de filtrer par nom (on veut souvent considérer tous les fichiers du répertoire courant), vous pouvez supprimer find et ajouter -R au premier grep:

grep -R -Z -l <patternYes> | xargs -0 grep -L <patternNo>
1
kirelagin

trouver . -maxdepth 1 -name "* .py" -exec grep -L "string-to-not-to-match" {} \;

Cette commande obtiendra tous les fichiers ".py" qui ne contiennent pas "string-not-to-match" dans le même répertoire.

0
Jahidfazal Patil