TheUnseen: Der Grund dafür, dass es nach fünf Ergebnissen beendet wird, wenn es an head -n 5 weitergeleitet wird, ist, dass head nach fünf Ergebnissen beendet wird. Beim Verlassen des Kopfes wird die Pipe geschlossen und sendet ein Signal an das Programm, das die Pipe zum Beenden einleitet. Es tut uns leid, dass Sie nicht direkt geantwortet haben. Anscheinend benötigen Sie 50 Ruf, um zu antworten.
Ruste
Antworten:
148
Mit GNU oder FreeBSD findkönnen Sie das -quitPrädikat verwenden:
find . ... -print -quit
Das NetBSD- findÄquivalent:
find . ... -print -exit
Wenn Sie nur den Namen drucken und davon ausgehen, dass die Dateinamen keine Zeilenumbrüche enthalten, können Sie Folgendes tun:
find . ... -print | head -n 1
Das wird nicht findnach dem ersten Match aufhören , sondern möglicherweise, je nach Timing und Pufferung nach dem zweiten Match oder (viel) später. Grundsätzlich findwird mit einem SIGPIPE beendet werden , wenn es um Ausgang etwas versucht , während headschon weg, da sie bereits gelesen und angezeigt , um die erste Zeile der Eingabe.
Beachten Sie, dass nicht alle Shells findnach headder Rückkehr auf diesen Befehl warten . Die Bourne-Shell- und AT & T-Implementierungen von ksh(wenn nicht interaktiv) und yash(nur wenn diese Pipeline der letzte Befehl in einem Skript ist) würden dies nicht tun, sodass sie im Hintergrund ausgeführt würden. Wenn Sie dieses Verhalten lieber in einer Shell sehen möchten, können Sie das oben stehende jederzeit ändern in:
(find . ... -print &) | head -n 1
Wenn Sie mehr tun als nur die Pfade der gefundenen Dateien zu drucken, können Sie diesen Ansatz ausprobieren:
find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;
(Ersetzen printfSie sie durch das, was Sie mit dieser Datei tun würden.)
Dies hat den Nebeneffekt find, dass ein Exit-Status zurückgegeben wird, der die Tatsache widerspiegelt, dass er getötet wurde.
Tatsächlich führt die Verwendung des Signals SIGPIPE anstelle von SIGTERM ( kill -s PIPEanstelle von kill) dazu, dass einige Shells über diesen Tod leiser sind (aber dennoch einen Ausgangsstatus ungleich Null zurückgeben würden).
Für den Fall, dass jemand testen muss, ob eine Datei mit den Prädikaten übereinstimmt, können if [[ $(find ... -print -quit) ]]; then ...Sie in Bash und GNU Find Folgendes tun: Es wird nur getestet, ob der Ausdruck überhaupt gefunden wird.
Tobia
@Tobia Besser, das $(…)Teil in Anführungszeichen zu setzen, wenn Sie nur die einzelnen Klammern verwenden ( [ … ]).
Phk
@phk Außer ich benutze nicht die einzelnen Klammern (weil sie schrecklich sind), deshalb brauche ich keine Anführungszeichen.
Tobia
2
@Tobia [ist ein Standardbefehl. Es ist nicht so sehr dieser Befehl, der schrecklich ist, sondern die Art und Weise, wie Bourne-ähnliche Shells Befehlszeilen analysieren. [[...]]ist ein ksh-Konstrukt, das in verschiedenen Shells eigene Probleme hat. Zum Beispiel, bis vor kurzem [[ $(...) ]]würde nicht funktionieren zsh(Sie brauchten [[ -n $(...) ]]). Abgesehen davon zsh, dass Sie Anführungszeichen in benötigen [[ $a = $b ]], [[ =~ ]]weist das inkompatible Unterschiede zwischen Implementierungen und sogar zwischen Versionen für Bash und einigen Bugs auf. Persönlich bevorzuge ich [.
Stéphane Chazelas
was ist ...? .
kyb
11
find . -name something -print -quit
Beendet die Suche nach dem ersten Treffer nach dem Drucken.
Suche nach einer bestimmten Anzahl von Übereinstimmungen beenden und Ergebnisse ausdrucken:
find . -name something -print | head -n 5
Überraschenderweise beendet head die Zeichenfolge nach 5 Übereinstimmungen, obwohl ich nicht weiß, wie oder warum.
Es ist sehr einfach zu testen. Lassen Sie finden suchen ein auf Wurzel , die Tausende, vielleicht sogar mehr Spiele während der Einnahme von mindestens einer Minute oder mehr zur Folge hätte. Wenn "find" in "head" umgeleitet wird, wird "find" nach der angegebenen Anzahl von Zeilen, die in head definiert sind, beendet (Standardeinstellung head zeigt 10, verwenden Sie "head -n", um Zeilen anzugeben).
Beachten Sie, dass dies beendet wird, nachdem "head -n" die angegebene Anzahl von Zeilenvorschubzeichen erreicht hat. Daher zählt jede Übereinstimmung, die mehrere Zeilenvorschubzeichen enthält, entsprechend.
Ich habe auch beobachtet, dass dieses "Programm endet, nachdem der Kopf mit seiner Ausgabe fertig ist" -Phänomen, aber nicht konsistent über die Shells hinweg. Ich denke, dass dies eine eigene Frage verdient - zum Glück für Bash ist die Antwort bereits bei StackOverflows Bash: Head & Tail-Verhalten mit Bash-Skript . Das gibt mir genügend Informationen, um zu dem Schluss zu kommen, dass es von der Reaktion auf SIGPIPE abhängt, ob das Programm im Hintergrund beendet wird oder weiter ausgeführt wird - das Töten ist die Standardeinstellung.
Salbei
Ich meinte "programmübergreifend" / "shells", aber anscheinend würde unix.stackexchange.com es vorziehen, dass ich dies als zweiten Kommentar protokolliere, anstatt meinen ersten Kommentar bearbeiten zu lassen (dies ist eine stapelaustauschspezifische Richtlinienentscheidung). Außerdem sehe ich jetzt, dass @Ruste diesen Effekt oben kommentiert hat, was mir anfangs nicht weitergeholfen hat, da ich direkt zu den Antworten gegangen bin ...
Salbei,
2
Zu Unterhaltungszwecken gibt es hier einen Lazy-Find-Generator in Bash. In diesem Beispiel wird ein Ring über die Dateien im aktuellen Verzeichnis generiert. Lies so viele du willst kill %+(vielleicht nur 1)
#!/usr/bin/env bash
unset -v files n
trap 'kill "$x_PID"' EXIT
coproc x while :; do
find . -type f -maxdepth 1 -exec sh -c "$(</dev/fd/3)" _ {} +
done 4<&0 <<\EOF 3<&0 <&4-
for x; do
read -r _
printf '%s\0' "$x"
done
EOF
while
echo >&${x[1]}
IFS= read -rd '' -u "$x" 'files[n++]'
do
printf '%q ' "${files[@]}"
echo
sleep .2
done
grep gibt auch zurück, wenn es mit dem Flag verwendet wird -m, also mit
find stuff | grep -m1 .
Es wird nach der ersten von find ausgegebenen Zeile zurückgegeben.
Der Unterschied zwischen diesem und diesem find stuff -print -quit | head -1ist, dass grep, wenn die Suche schnell genug ist, möglicherweise nicht in der Lage ist, den Prozess rechtzeitig anzuhalten (obwohl dies nicht wirklich wichtig ist), während es bei einer langen Suche Zeit spart, eine Menge nicht benötigter Dokumente zu drucken Linien.
dies funktioniert stattdessen mit busybox find, obwohl da busybox grep auch -mnicht wirklich benötigt wird
Dies gibt eine Nachricht darüber aus, dass der Suchvorgang das (normalerweise) sigterm-Signal empfangen hat, aber diese Ausgabe gehört zur laufenden Shell, nicht zum find-Befehl, sodass sie nicht mit der Befehlsausgabe in Konflikt gerät, was bedeutet, dass Pipes oder Umleitungen nur die Zeile ausgeben von find abgestimmt.
Antworten:
Mit GNU oder FreeBSD
find
können Sie das-quit
Prädikat verwenden:Das NetBSD-
find
Äquivalent:Wenn Sie nur den Namen drucken und davon ausgehen, dass die Dateinamen keine Zeilenumbrüche enthalten, können Sie Folgendes tun:
Das wird nicht
find
nach dem ersten Match aufhören , sondern möglicherweise, je nach Timing und Pufferung nach dem zweiten Match oder (viel) später. Grundsätzlichfind
wird mit einem SIGPIPE beendet werden , wenn es um Ausgang etwas versucht , währendhead
schon weg, da sie bereits gelesen und angezeigt , um die erste Zeile der Eingabe.Beachten Sie, dass nicht alle Shells
find
nachhead
der Rückkehr auf diesen Befehl warten . Die Bourne-Shell- und AT & T-Implementierungen vonksh
(wenn nicht interaktiv) undyash
(nur wenn diese Pipeline der letzte Befehl in einem Skript ist) würden dies nicht tun, sodass sie im Hintergrund ausgeführt würden. Wenn Sie dieses Verhalten lieber in einer Shell sehen möchten, können Sie das oben stehende jederzeit ändern in:Wenn Sie mehr tun als nur die Pfade der gefundenen Dateien zu drucken, können Sie diesen Ansatz ausprobieren:
(Ersetzen
printf
Sie sie durch das, was Sie mit dieser Datei tun würden.)Dies hat den Nebeneffekt
find
, dass ein Exit-Status zurückgegeben wird, der die Tatsache widerspiegelt, dass er getötet wurde.Tatsächlich führt die Verwendung des Signals SIGPIPE anstelle von SIGTERM (
kill -s PIPE
anstelle vonkill
) dazu, dass einige Shells über diesen Tod leiser sind (aber dennoch einen Ausgangsstatus ungleich Null zurückgeben würden).quelle
if [[ $(find ... -print -quit) ]]; then ...
Sie in Bash und GNU Find Folgendes tun: Es wird nur getestet, ob der Ausdruck überhaupt gefunden wird.$(…)
Teil in Anführungszeichen zu setzen, wenn Sie nur die einzelnen Klammern verwenden ([ … ]
).[
ist ein Standardbefehl. Es ist nicht so sehr dieser Befehl, der schrecklich ist, sondern die Art und Weise, wie Bourne-ähnliche Shells Befehlszeilen analysieren.[[...]]
ist ein ksh-Konstrukt, das in verschiedenen Shells eigene Probleme hat. Zum Beispiel, bis vor kurzem[[ $(...) ]]
würde nicht funktionierenzsh
(Sie brauchten[[ -n $(...) ]]
). Abgesehen davonzsh
, dass Sie Anführungszeichen in benötigen[[ $a = $b ]]
,[[ =~ ]]
weist das inkompatible Unterschiede zwischen Implementierungen und sogar zwischen Versionen für Bash und einigen Bugs auf. Persönlich bevorzuge ich[
....
? .Beendet die Suche nach dem ersten Treffer nach dem Drucken.
Suche nach einer bestimmten Anzahl von Übereinstimmungen beenden und Ergebnisse ausdrucken:
Überraschenderweise beendet head die Zeichenfolge nach 5 Übereinstimmungen, obwohl ich nicht weiß, wie oder warum.
Es ist sehr einfach zu testen. Lassen Sie finden suchen ein auf Wurzel , die Tausende, vielleicht sogar mehr Spiele während der Einnahme von mindestens einer Minute oder mehr zur Folge hätte. Wenn "find" in "head" umgeleitet wird, wird "find" nach der angegebenen Anzahl von Zeilen, die in head definiert sind, beendet (Standardeinstellung head zeigt 10, verwenden Sie "head -n", um Zeilen anzugeben).
Beachten Sie, dass dies beendet wird, nachdem "head -n" die angegebene Anzahl von Zeilenvorschubzeichen erreicht hat. Daher zählt jede Übereinstimmung, die mehrere Zeilenvorschubzeichen enthält, entsprechend.
quelle
Zu Unterhaltungszwecken gibt es hier einen Lazy-Find-Generator in Bash. In diesem Beispiel wird ein Ring über die Dateien im aktuellen Verzeichnis generiert. Lies so viele du willst
kill %+
(vielleicht nur 1)quelle
grep gibt auch zurück, wenn es mit dem Flag verwendet wird
-m
, also mitEs wird nach der ersten von find ausgegebenen Zeile zurückgegeben.
Der Unterschied zwischen diesem und diesem
find stuff -print -quit | head -1
ist, dass grep, wenn die Suche schnell genug ist, möglicherweise nicht in der Lage ist, den Prozess rechtzeitig anzuhalten (obwohl dies nicht wirklich wichtig ist), während es bei einer langen Suche Zeit spart, eine Menge nicht benötigter Dokumente zu drucken Linien.dies funktioniert stattdessen mit busybox find, obwohl da busybox grep auch
-m
nicht wirklich benötigt wirdDies gibt eine Nachricht darüber aus, dass der Suchvorgang das (normalerweise) sigterm-Signal empfangen hat, aber diese Ausgabe gehört zur laufenden Shell, nicht zum find-Befehl, sodass sie nicht mit der Befehlsausgabe in Konflikt gerät, was bedeutet, dass Pipes oder Umleitungen nur die Zeile ausgeben von find abgestimmt.
quelle