Comment grep des milliers de fichiers dans un répertoire pour des centaines de chaînes dans un fichier


11

J'essaie de composer une grepdéclaration et cela me tue. Je suis également fatigué de l' arguments list too longerreur. J'ai un fichier, appelons-le subset.txt. Il contient des centaines de lignes avec des chaînes spécifiques telles que MO43312948. Dans mon répertoire d'objets, j'ai des milliers de fichiers et je dois copier tous les fichiers qui contiennent les chaînes répertoriées subset.txtdans un autre répertoire.

J'essayais de commencer avec cela pour simplement retourner les fichiers correspondants du répertoire des objets.

grep -F "$(subset.txt)" /objects/*

Je reçois toujours `bash: / bin / grep: La liste des arguments est trop longue``


6
Pourquoi avez-vous mis "$(subset.txt)"la commande comme ça? C'est une substitution de commande , qui fera de votre shell exécuter subset.txt (comme si elle était une commande ou d'un script).
JigglyNaga

Réponses:


23

Vous pouvez passer un répertoire en tant que cible à grepavec -Ret un fichier de modèles d'entrée avec -f:

  -f FILE, --file=FILE
          Obtain patterns from FILE, one per line.  If this option is used
          multiple  times  or  is  combined with the -e (--regexp) option,
          search for all patterns given.  The  empty  file  contains  zero
          patterns, and therefore matches nothing.

   -R, --dereference-recursive
          Read all files under each directory,  recursively.   Follow  all
          symbolic links, unlike -r.

Vous cherchez donc:

grep -Ff subset.txt -r objects/

Vous pouvez obtenir la liste des fichiers correspondants avec:

grep -Flf subset.txt -r objects/

Donc, si votre liste finale n'est pas trop longue, vous pouvez simplement faire:

 mv $(grep -Flf subset.txt -r objects/) new_dir/

Si cela renvoie une argument list too longerreur, utilisez:

grep -Flf subset.txt -r objects/ | xargs -I{} mv {} bar/

Et si vos noms de fichiers peuvent contenir des espaces ou d'autres caractères étranges, utilisez (en supposant GNU grep):

grep -FZlf subset.txt -r objects/ | xargs -0I{} mv {} bar/

Enfin, si vous souhaitez exclure des fichiers binaires, utilisez:

grep -IFZlf subset.txt -r objects/ | xargs -0I{} mv {} bar/

… Ou pour éviter potentiellement des milliers d' mvinvocations avec un argument chacun: ... | xargs -0 mv -t bar/(en supposant que votre mvsupporte l' -toption).
David Foerster

11

utilisation

grep -F -f subset.txt 

pour dire à grep de lire le subset.txtfichier.

vous pouvez utiliser find pour parcourir le fichier.

find . -type f -exec grep -F -f subset.txt {} \;

ou

find . -type f -exec grep -F -f subset.txt {}  +

Y a-t-il un avantage à utiliser findau lieu de -rfaire un filtrage supplémentaire?
phk

1
@phk grep -rrecherche dans des liens symboliques vers des fichiers normaux, ce qui peut être souhaitable ou non (s'ils pointent à l'intérieur de la même arborescence, vous recherchez deux fois le même fichier; s'ils pointent à l'extérieur, vous recherchez un fichier qui peut ou non être souhaité).
Gilles 'SO- arrête d'être méchant'

Les versions modernes de grepont des options pour contrôler leur interaction avec les liens symboliques ( man greppour déterminer les spécificités du système actuel). Un récursif grepsera beaucoup plus rapide que l'exécution grepindividuelle sur chaque fichier via find.
Perry

1
@Perry êtes-vous sûr de cela? Pourquoi? Notez également que cette réponse utilise -exec +, donc elle regroupera les fichiers et n'exécutera pas un grep par fichier.
terdon

Je suis corrigé, je n'étais pas au courant des différentes sémantiques de -exec {} +vs -exec {} \;... vous apprenez quelque chose de nouveau tous les jours (je ne vois toujours pas de raison pour laquelle un seul récursif grepne sera pas plus rapide que plusieurs greps en findraison de la création de processus et de l'analyse syntaxique des modèles, mais je n’avez pas de chiffres précis à vous donner pour le confirmer)
Perry

3

Si vous voulez accélérer encore plus grep, vous pouvez définir les paramètres régionaux dans votre shell avant de l'exécuter, c'est-à-dire utiliser "LC_ALL = c". Cela sera hérité de grep et désactivera le traitement Unicode lorsqu'il n'est pas nécessaire et dans certains cas, peut accélérer considérablement grep. Un excellent blog documentant cela peut être trouvé à http://www.inmotionhosting.com/support/website/ssh/speed-up-grep-searches-with-lc-all . Cette astuce peut également accélérer les scripts shell bash, pas seulement grep.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.