TheUnseen: Powodem, dla którego kończy pracę po pięciu wynikach po podłączeniu do głowicy -n 5, jest to, że głowa wychodzi po pięciu wynikach. Kiedy głowica wychodzi, rura zamyka się i wysyła sygnał do programu, który się do niej wpina, aby również się zakończył. Przepraszam, że nie odpowiadam bezpośrednio na ciebie, najwyraźniej potrzebujesz 50 reputacji, aby odpowiedzieć.
Ruste
Odpowiedzi:
148
W GNU lub FreeBSD findmożesz użyć -quitpredykatu:
find . ... -print -quit
Odpowiednik NetBSD find:
find . ... -print -exit
Jeśli wszystko, co robisz, to drukujesz nazwę i zakładając, że nazwy plików nie zawierają znaków nowej linii, możesz:
find . ... -print | head -n 1
Nie zatrzyma się to findpo pierwszym meczu, ale możliwe, że w zależności od czasu i buforowania przy drugim meczu lub (znacznie) później. Zasadniczo findzostanie zakończone SIGPIPE, gdy spróbuje coś wyrenderować, gdy headjuż go nie ma, ponieważ już odczytał i wyświetlił pierwszy wiersz danych wejściowych.
Zauważ, że nie wszystkie powłoki będą czekać na to findpolecenie po headjego zwróceniu. Implementacje powłoki Bourne'a i implementacji AT&T ksh(gdy nie są interaktywne) i yash(tylko jeśli ten potok jest ostatnim poleceniem w skrypcie) nie, pozostawiając działające w tle. Jeśli wolisz zobaczyć takie zachowanie w dowolnej powłoce, zawsze możesz zmienić powyższe na:
(find . ... -print &) | head -n 1
Jeśli robisz więcej niż drukowanie ścieżek znalezionych plików, możesz wypróbować następujące podejście:
find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;
(zamień na printfcokolwiek, co robisz z tym plikiem).
Ma to jednak efekt uboczny findzwrócenia statusu wyjścia odzwierciedlającego fakt, że został zabity.
Właściwie użycie sygnału SIGPIPE zamiast SIGTERM ( kill -s PIPEzamiast kill) spowoduje, że niektóre pociski będą milczały na temat tej śmierci (ale nadal zwrócą niezerowy status wyjścia).
W przypadku, gdy ktoś musi sprawdzić, czy jakiś plik pasuje do predykatów, zatrzymując się, gdy tylko zostanie znaleziony, w Bash i GNU Find możesz to zrobić: if [[ $(find ... -print -quit) ]]; then ...Testuje tylko, czy w ogóle coś wydrukowano.
Tobia,
@Tobia Lepiej wstawić $(…)część w cudzysłów, jeśli używasz tylko pojedynczych nawiasów ( [ … ]).
phk
@phk Tyle że nie używam pojedynczych nawiasów (ponieważ są okropne), więc nie muszę używać cudzysłowów.
Tobia,
2
@Tobia, [to standardowe polecenie. To nie tyle straszne polecenie, co sposób, w jaki powłoki Bourne'a analizują wiersze poleceń. [[...]]jest konstrukcją ksh, która ma własne problemy w różnych powłokach. Na przykład do niedawna [[ $(...) ]]nie działał zsh(trzeba [[ -n $(...) ]]). Z wyjątkiem zsh, potrzebujesz cytatów [[ $a = $b ]], [[ =~ ]]ma niezgodne różnice między implementacjami, a nawet między wersjami bash i kilkoma błędami w niektórych. Osobiście wolę [.
Stéphane Chazelas
co jest ...? .
Kyb
11
find . -name something -print -quit
Kończy wyszukiwanie po pierwszym dopasowaniu po wydrukowaniu.
Zakończ wyszukiwanie po określonej liczbie dopasowań i wydrukuj wyniki:
find . -name something -print | head -n 5
Zaskakujące - głowa kończy teraz ciąg po 5 meczach, chociaż nie wiem jak i dlaczego.
Jest to bardzo łatwe do przetestowania. Po prostu pozwól odnaleźć szukać na korzeń, który powodowałby tysiące, a może nawet więcej meczów podczas przyjmowania co najmniej minutę lub więcej. Ale po podłączeniu do „head” „find” zakończy się po określonej liczbie linii zdefiniowanych w head (domyślna głowa pokazuje 10, użyj „head -n”, aby określić linie).
Zauważ, że zakończy się ono, gdy „head -n” osiągnie określoną liczbę znaków nowej linii, a zatem każde dopasowanie zawierające wiele znaków nowej linii będzie odpowiednio liczone.
Zauważyłem również, że ten program „kończy się po zakończeniu działania głowicy wraz z wyjściem”, ale nie konsekwentnie w powłokach. Myślę, że to zasługuje na własne pytanie - na szczęście w przypadku bashu odpowiedź jest już dostępna w grze Bash: Head & Tail StackOverflow ze skryptem bash . Daje mi to wystarczającą ilość informacji, aby stwierdzić, że to, czy program zakończy się lub będzie kontynuował działanie w tle, zależy od jego odpowiedzi na SIGPIPE - zabijanie jest domyślne.
mędrzec
Miałem na myśli „w * programach * / powłokach”, ale najwyraźniej unix.stackexchange.com wolałbym rejestrować to jako drugi komentarz niż pozwolić na edycję mojego pierwszego komentarza (jest to zmiana stosu, decyzja dotycząca konkretnej witryny). Widzę też teraz, że @Ruste skomentował ten efekt na górze, co początkowo mi nie pomogło, ponieważ od razu poszedłem do odpowiedzi ...
mędrzec
2
Dla celów rozrywkowych, oto leniwy generator znajdujący się w Bash. Ten przykład generuje pierścień nad plikami w bieżącym katalogu. Przeczytaj tyle, ile chcesz kill %+(może tylko 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 zwraca również, jeśli jest używane z flagą -m, więc z
find stuff | grep -m1 .
powróci po pierwszym wierszu wydrukowanym przez find.
Różnica między tym a tym, find stuff -print -quit | head -1że jeśli wyszukiwanie jest wystarczająco szybkie, grep może nie być w stanie zatrzymać procesu na czas (nie ma to jednak znaczenia), a jeśli wyszukiwanie jest długie, zaoszczędzę znaleźć wiele niepotrzebnych wydruków linie.
to zamiast tego działa z funkcją busybox find, chociaż skoro busybox grep również -mgo ma , to nie jest tak naprawdę potrzebne
to wypluje komunikat o tym, że proces znajdowania otrzymał (zwykle) sygnał sigterm, ale to wyjście należy do działającej powłoki, a nie polecenia find, więc nie zadziera z wyjściem polecenia, co oznacza, że potoki lub przekierowania wyprowadzą tylko linię dopasowane przez find.
Odpowiedzi:
W GNU lub FreeBSD
find
możesz użyć-quit
predykatu:Odpowiednik NetBSD
find
:Jeśli wszystko, co robisz, to drukujesz nazwę i zakładając, że nazwy plików nie zawierają znaków nowej linii, możesz:
Nie zatrzyma się to
find
po pierwszym meczu, ale możliwe, że w zależności od czasu i buforowania przy drugim meczu lub (znacznie) później. Zasadniczofind
zostanie zakończone SIGPIPE, gdy spróbuje coś wyrenderować, gdyhead
już go nie ma, ponieważ już odczytał i wyświetlił pierwszy wiersz danych wejściowych.Zauważ, że nie wszystkie powłoki będą czekać na to
find
polecenie pohead
jego zwróceniu. Implementacje powłoki Bourne'a i implementacji AT&Tksh
(gdy nie są interaktywne) iyash
(tylko jeśli ten potok jest ostatnim poleceniem w skrypcie) nie, pozostawiając działające w tle. Jeśli wolisz zobaczyć takie zachowanie w dowolnej powłoce, zawsze możesz zmienić powyższe na:Jeśli robisz więcej niż drukowanie ścieżek znalezionych plików, możesz wypróbować następujące podejście:
(zamień na
printf
cokolwiek, co robisz z tym plikiem).Ma to jednak efekt uboczny
find
zwrócenia statusu wyjścia odzwierciedlającego fakt, że został zabity.Właściwie użycie sygnału SIGPIPE zamiast SIGTERM (
kill -s PIPE
zamiastkill
) spowoduje, że niektóre pociski będą milczały na temat tej śmierci (ale nadal zwrócą niezerowy status wyjścia).źródło
if [[ $(find ... -print -quit) ]]; then ...
Testuje tylko, czy w ogóle coś wydrukowano.$(…)
część w cudzysłów, jeśli używasz tylko pojedynczych nawiasów ([ … ]
).[
to standardowe polecenie. To nie tyle straszne polecenie, co sposób, w jaki powłoki Bourne'a analizują wiersze poleceń.[[...]]
jest konstrukcją ksh, która ma własne problemy w różnych powłokach. Na przykład do niedawna[[ $(...) ]]
nie działałzsh
(trzeba[[ -n $(...) ]]
). Z wyjątkiemzsh
, potrzebujesz cytatów[[ $a = $b ]]
,[[ =~ ]]
ma niezgodne różnice między implementacjami, a nawet między wersjami bash i kilkoma błędami w niektórych. Osobiście wolę[
....
? .Kończy wyszukiwanie po pierwszym dopasowaniu po wydrukowaniu.
Zakończ wyszukiwanie po określonej liczbie dopasowań i wydrukuj wyniki:
Zaskakujące - głowa kończy teraz ciąg po 5 meczach, chociaż nie wiem jak i dlaczego.
Jest to bardzo łatwe do przetestowania. Po prostu pozwól odnaleźć szukać na korzeń, który powodowałby tysiące, a może nawet więcej meczów podczas przyjmowania co najmniej minutę lub więcej. Ale po podłączeniu do „head” „find” zakończy się po określonej liczbie linii zdefiniowanych w head (domyślna głowa pokazuje 10, użyj „head -n”, aby określić linie).
Zauważ, że zakończy się ono, gdy „head -n” osiągnie określoną liczbę znaków nowej linii, a zatem każde dopasowanie zawierające wiele znaków nowej linii będzie odpowiednio liczone.
źródło
Dla celów rozrywkowych, oto leniwy generator znajdujący się w Bash. Ten przykład generuje pierścień nad plikami w bieżącym katalogu. Przeczytaj tyle, ile chcesz
kill %+
(może tylko 1)źródło
grep zwraca również, jeśli jest używane z flagą
-m
, więc zpowróci po pierwszym wierszu wydrukowanym przez find.
Różnica między tym a tym,
find stuff -print -quit | head -1
że jeśli wyszukiwanie jest wystarczająco szybkie, grep może nie być w stanie zatrzymać procesu na czas (nie ma to jednak znaczenia), a jeśli wyszukiwanie jest długie, zaoszczędzę znaleźć wiele niepotrzebnych wydruków linie.to zamiast tego działa z funkcją busybox find, chociaż skoro busybox grep również
-m
go ma , to nie jest tak naprawdę potrzebneto wypluje komunikat o tym, że proces znajdowania otrzymał (zwykle) sygnał sigterm, ale to wyjście należy do działającej powłoki, a nie polecenia find, więc nie zadziera z wyjściem polecenia, co oznacza, że potoki lub przekierowania wyprowadzą tylko linię dopasowane przez find.
źródło