Grep nur das erste Match und hör auf

328

Ich suche ein Verzeichnis rekursiv mit grep mit den folgenden Argumenten in der Hoffnung, nur die erste Übereinstimmung zurückzugeben. Leider gibt es mehr als eins zurück - tatsächlich zwei, als ich das letzte Mal nachgesehen habe. Es scheint, als hätte ich zu viele Argumente, insbesondere ohne das gewünschte Ergebnis zu erzielen. : - /

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

kehrt zurück:

Pulsanti Operietur
Pulsanti Operietur

Vielleicht ist grep nicht der beste Weg, dies zu tun? Du sagst mir, vielen Dank.

Tim Kamm
quelle

Antworten:

510

-m 1bedeutet, dass die erste Übereinstimmung in einer bestimmten Datei zurückgegeben wird. Es wird jedoch weiterhin in anderen Dateien gesucht. Wenn zwei oder mehr Übereinstimmungen in derselben Zeile vorhanden sind, werden alle angezeigt.

Sie können verwenden head -1, um dieses Problem zu lösen:

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

Erklärung jeder Grep-Option:

-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
quelle
genial! Vielen Dank. Übrigens - sind all diese anderen Argumente notwendig, die ich im Befehl habe? und was ist, wenn ich es nicht zufällig pfeifen kann (nur für den Fall).
Tim Kamm
2
Ich denke nicht, dass sie notwendig sind (außer -roffensichtlich), aber sie sollten nicht weh tun (ich würde es aber nicht benutzen -a)
mvp
3
Genau das, was ich brauchte. Mein Muster wurde zweimal in derselben Zeile gefunden und hat grep -m 1aus diesem Grund beide Instanzen zurückgegeben. |head -1Ich habe es gelöst!
Harperville
6
@Chris_Rands Das genaue Verhalten hängt von der Shell ab, in der Sie ausgeführt werden. Head wird beendet, sobald es auf die erste Zeile trifft. grep wird beim nächsten Versuch, nach dem Beenden von head zu schreiben, beendet. Einige Shells warten, bis alle Elemente einer Pipeline fertig sind, andere führen dazu, dass die gesamte Pipe heruntergefahren wird, sobald das letzte Programm in der Pipe beendet wird.
Puhlen
1
@ 3Qn, ich verstehe deinen Kommentar nicht : first not first from result. Diese Antwort druckt die erste Übereinstimmung in einer beliebigen Datei und stoppt. Was hast du noch erwartet?
MVP
31

Sie können das grepErgebnis headin Verbindung mit stdbuf weiterleiten .

Beachten Sie, dass Sie Folgendes verwenden müssen stdbuf, um sicherzustellen, dass grepdie Ausgabe nicht gepuffert wird, um das Stoppen nach dem N-ten Match sicherzustellen :

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

Sobald eine headLeitung verbraucht ist, wird sie beendet und grepempfangen, SIGPIPEda sie noch etwas an die Pipe ausgibt, während sie headweg war.

Dies setzte voraus, dass keine Dateinamen Zeilenumbrüche enthalten.

Venkat Kotra
quelle
Ich versuche, diese Lösung zu verwenden, um in einer großen Anzahl von Archivdateien zu suchen xargs: find . -name '*.gz' | xargs -I '{}' stdbuf -oL zgrep -al 'pattern' {} | head -n 1. Dies endet jedoch nicht beim ersten Spiel. Irgendein Rat?
DKroot
1
Würde grepdie --line-bufferedOption nicht den Pufferaufwand verhindern, ohne ein zusätzliches Dienstprogramm aufzurufen?
David
23

Mein grep-a-like-Programm ackverfügt über eine -1Option, die beim ersten Spiel endet, das irgendwo gefunden wurde. Es unterstützt auch das -m 1, worauf sich @mvp bezieht. Ich habe es dort abgelegt, denn wenn ich einen großen Quellcodebaum durchsuche, um etwas zu finden, von dem ich weiß, dass es nur in einer Datei vorhanden ist, ist es nicht erforderlich, es zu finden und muss Strg-C drücken.

Andy Lester
quelle
Sie würden also sagen, dass ack schneller ist als grep? Ich bin auch sehr besorgt über den Geschwindigkeitsfaktor.
Tim Kamm
1
ack kann schneller sein als grep, je nachdem, was Sie suchen. Bitte beachten Sie, dass es bei ack um die Suche nach Quellcode geht. Wenn Sie nach allgemeinen Dateien suchen möchten, ist dies weniger gut, zumindest in ack 1.x. Lesen Sie mehr über ack und sehen Sie, ob es vielleicht Ihren Bedürfnissen entspricht.
Andy Lester
2
Ich habe Ack für eine lange Zeit benutzt, aber vor kurzem zu The Silver Searcher gewechselt, den ich als schneller
empfinde,
Ich glaube, dies sollte die einzige Antwort sein, da das OP sagte, er wolle es mit grep machen, aber die andere Antwort verwendet head (beide funktionieren natürlich), aber es gibt einige eingebettete / selbst erstellte Umgebungen mit minimalen Tools, in denen grep üblich ist und tail / Kopf ist nicht.
Areeb Soo Yasir
Erwähnenswert ist, dass agdies schnell gehen kann, aber es gibt nicht die -1Option, die in diesem Fall nützlich ist
jja
3

Sie können den folgenden Befehl verwenden, wenn Sie die gesamte Zeile und den Dateinamen drucken möchten, wenn ein bestimmtes Wort im aktuellen Verzeichnis vorkommt, das Sie suchen.

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

Ein einzelner Liner mit find:

find -type f -exec grep -lm1 "PATTERN" {} \; -a -quit
Yam Marcovic
quelle
6
Dies wird sehr langsam sein, da find für jede gefundene Datei eine Kopie von grep erzeugt. grep -rarbeitet viel schneller - es ist nur eine Kopie, die Verzeichnisdurchläufe durchführt.
MVP
Wahr; find kann jedoch so angepasst werden, dass nur gefilterte Ergebnisse verarbeitet werden, wodurch der Vorgang viel schneller als bei einem Catch-All-Grep wird. Kommt auf den Kontext an.
Yam Marcovic