Jak zatrzymać polecenie find po pierwszym dopasowaniu?

131

Czy istnieje sposób, aby zmusić findpolecenie do zatrzymania zaraz po znalezieniu pierwszego dopasowania?

kubek kawy
źródło
4
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).

Stéphane Chazelas
źródło
3
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.

TheUnseen
źródło
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
ormaaj
źródło
1

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

find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;

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.

odtąd
źródło