Grep seulement le premier match et arrête

329

J'effectue une recherche récursive dans un répertoire en utilisant grep avec les arguments suivants dans l'espoir de ne renvoyer que la première correspondance. Malheureusement, il en retourne plus d'un - en fait deux la dernière fois que j'ai regardé. Il semble que j'ai trop d'arguments, surtout sans obtenir le résultat souhaité. : - /

# grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/directory

Retour:

Pulsanti Operietur
Pulsanti Operietur

Peut-être que grep n'est pas la meilleure façon de le faire? Vous me dites, merci beaucoup.

Tim Kamm
la source

Réponses:

512

-m 1signifie retourner la première correspondance dans un fichier donné. Mais il continuera toujours à chercher dans d'autres fichiers. De plus, s'il y en a deux ou plus correspondant sur la même ligne, tous seront affichés.

Vous pouvez utiliser head -1pour résoudre ce problème:

grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -1

explication de chaque option grep:

-o, --only-matching, print only the matched part of the line (instead of the entire line)
-a, --text, process a binary file as if it were text
-m 1, --max-count, stop reading a file after 1 matching line
-h, --no-filename, suppress the prefixing of file names on output
-r, --recursive, read all files under a directory recursively
mvp
la source
impressionnant! Merci. btw - tous ces autres arguments sont-ils nécessaires que j'ai dans la commande? et si je ne peux pas le faire par hasard (juste au cas où).
Tim Kamm
2
Je ne pense pas qu'ils soient nécessaires (sauf -révidemment), mais ils ne devraient pas faire de mal (je ne les utiliserais pas -acependant)
mvp
3
Exactement ce dont j'avais besoin. Mon modèle a été trouvé deux fois sur la même ligne et a grep -m 1renvoyé les deux instances à cause de cela. |head -1résolu!
harperville
6
@Chris_Rands le comportement exact dépend du shell dans lequel vous exécutez. Head quittera dès qu'il rencontrera la première ligne. grep se fermera la prochaine fois qu'il tentera d'écrire après la sortie de head. Certains shells attendront la fin de tous les éléments d'un pipeline, d'autres entraîneront l'arrêt complet du tuyau dès la sortie du dernier programme du tuyau.
puhlen
1
@ 3Qn, je ne comprends pas votre commentaire: first not first from result. Cette réponse imprime la première correspondance dans n'importe quel fichier et s'arrête. À quoi d'autre vous attendiez-vous?
mvp
31

Vous pouvez diriger legrep résultat vers headen conjonction avec stdbuf .

Notez que pour garantir l'arrêt après la Nième correspondance, vous devez utiliser stdbufpour vous assurer de grepne pas tamponner sa sortie:

stdbuf -oL grep -rl 'pattern' * | head -n1
stdbuf -oL grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -n1
stdbuf -oL grep -nH -m 1 -R "django.conf.urls.defaults" * | head -n1

Dès qu'il headconsomme 1 ligne, il s'est terminé et greprecevra SIGPIPEcar il a toujours headsorti quelque chose vers le tuyau alors qu'il était parti.

Cela suppose qu'aucun nom de fichier ne contient de nouvelle ligne.

Venkat Kotra
la source
Je suis en train d'adopter cette solution pour la recherche dans un grand nombre de fichiers d' archive avec xargs: find . -name '*.gz' | xargs -I '{}' stdbuf -oL zgrep -al 'pattern' {} | head -n 1. Cependant, cela ne se termine pas lors du premier match. Aucun conseil?
DKroot
1
grepL' --line-bufferedoption n'empêcherait -elle pas la surcharge du tampon sans appeler un utilitaire supplémentaire?
David
23

Mon programme grep-a-like acka une -1option qui s'arrête à la première correspondance trouvée n'importe où. Il prend également en charge le -m 1@mvp. Je l'ai mis là-dedans parce que si je recherche un grand arbre de code source pour trouver quelque chose que je sais exister dans un seul fichier, il n'est pas nécessaire de le trouver et je dois appuyer sur Ctrl-C.

Andy Lester
la source
vous diriez donc qu'ack est plus rapide que grep? Je suis également très préoccupé par le facteur vitesse.
Tim Kamm
1
ack peut être plus rapide que grep, selon ce que vous recherchez. Veuillez noter que l'ack concerne la recherche de code source. Si vous cherchez à rechercher des fichiers généraux, c'est moins bon à cela, au moins dans ack 1.x. Allez lire sur ack et voyez si cela correspond à vos besoins.
Andy Lester
2
J'utilise Ack depuis longtemps, mais je suis récemment passé au chercheur d'argent que je trouve plus rapide, Ack
guy.gc
Je pense que cela devrait être la seule réponse parce que l'OP a dit qu'il voulait que cela soit fait avec grep, mais l'autre réponse utilise head (les deux fonctionnent bien sûr) mais il existe des environnements intégrés / auto-créés avec des outils minimaux où grep est commun et tail / la tête ne l'est pas.
Areeb Soo Yasir
Il convient de mentionner que cela agpourrait être rapide, mais il n'a pas l' -1option qui est utile dans ce cas
jja
4

Vous pouvez utiliser la commande ci-dessous si vous souhaitez imprimer la ligne entière et le nom de fichier si l'occurrence d'un mot particulier dans le répertoire actuel que vous recherchez.

grep -m 1 -r "Not caching" * | head -1
Gaurav londhe
la source
2

Une doublure unique, utilisant find:

find -type f -exec grep -lm1 "PATTERN" {} \; -a -quit
Yam Marcovic
la source
6
Cela va être très lent, car find générera une copie de grep pour chaque fichier trouvé. grep -rfonctionne beaucoup plus rapidement - sa seule copie qui effectue des traversées de répertoire.
mvp
Vrai; bien que find puisse être personnalisé pour ne fonctionner que sur des résultats filtrés, ce qui peut alors rendre l'opération beaucoup plus rapide qu'un grep fourre-tout. Dépend du contexte.
Yam Marcovic