Ich habe ein Verzeichnis mit ~1M Dateien und muss nach bestimmten Mustern suchen. Ich weiß, wie man es für alle Dateien macht:
find /path/ -exec grep -H -m 1 'pattern' {} ;
Die volle Leistung ist nicht erwünscht (zu langsam). Mehrere erste Treffer sind in Ordnung, also habe ich versucht, die Anzahl der Zeilen zu begrenzen:
find /path/ -exec grep -H -m 1 'pattern' {} ; | head -n 5
Dies ergibt 5 Zeilen gefolgt von
find: `grep' terminated by signal 13
und find
arbeitet weiter. Das ist hier gut erklärt. Ich habe versucht quit
Aktion:
find /path/ -exec grep -H -m 1 'pattern' {} ; -quit
Dies gibt nur die erste Übereinstimmung aus.
Ist es möglich, die Ausgabe von find auf eine bestimmte Anzahl von Ergebnissen zu begrenzen (wie das Bereitstellen eines Arguments zum quit
ähnlich wie head -n
)?
Akzeptierte Antwort:
Da Sie bereits GNU-Erweiterungen verwenden (-quit
, -H
, -m1
), können Sie genauso gut GNU grep
verwenden 's -r
Option, zusammen mit --line-buffered
Daher gibt es die Übereinstimmungen aus, sobald sie gefunden werden, sodass es wahrscheinlicher ist, dass es von einem SIGPIPE getötet wird, sobald es die 6. Zeile schreibt:
grep -rHm1 --line-buffered pattern /path | head -n 5
Mit find
, müssten Sie wahrscheinlich so etwas tun:
find /path -type f -exec sh -c '
grep -Hm1 --line-buffered pattern "[email protected]"
[ "$(kill -l "$?")" = PIPE ] && kill -s PIPE "$PPID"
' sh {} + | head -n 5
Das heißt, umschließen Sie grep
in sh
(Sie möchten immer noch so wenige grep
ausführen Aufrufe wie möglich, daher der {} +
) und haben sh
töte seinen Elternteil (find
), wenn grep
stirbt an einem SIGPIPE.
Ein anderer Ansatz könnte darin bestehen, xargs
zu verwenden als Alternative zu -exec {} +
. xargs
wird sofort beendet, wenn ein Befehl, den es erzeugt, durch ein Signal stirbt, also in:
find . -type f -print0 |
xargs -r0 grep -Hm1 --line-buffered pattern |
head -n 5
(-r
und -0
GNU-Erweiterungen sind). Sobald grep
schreibt in die kaputte Pipe, beides grep
und xargs
wird beendet und find
wird sich auch selbst beenden, wenn es das nächste Mal etwas danach druckt. Ausführen von find
unter stdbuf -oL
könnte es früher passieren lassen.
Eine POSIX-Version könnte sein:
trap - PIPE # restore default SIGPIPE handler in case it was disabled
RE=pattern find /path -type f -exec sh -c '
for file do
awk '''
$0 ~ ENVIRON["RE"] {
print FILENAME ": " $0
exit
}''' < "$file"
if [ "$(kill -l "$?")" = PIPE ]; then
kill -s PIPE "$PPID"
exit
fi
done' sh {} + | head -n 5
Sehr ineffizient, da es mehrere Befehle für jede Datei ausführt.
Verwandte:Ubuntu – Wie sperrt man die Lüftergeschwindigkeit für AMD-GPU in Ubuntu 20.04?