Czy istnieje sposób, aby zmusić find
polecenie do zatrzymania zaraz po znalezieniu pierwszego dopasowania?
Czy istnieje sposób, aby zmusić find
polecenie do zatrzymania zaraz po znalezieniu pierwszego dopasowania?
Odpowiedzi:
W GNU lub FreeBSD find
możesz użyć -quit
predykatu:
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 find
po pierwszym meczu, ale możliwe, że w zależności od czasu i buforowania przy drugim meczu lub (znacznie) później. Zasadniczo find
zostanie zakończone SIGPIPE, gdy spróbuje coś wyrenderować, gdy head
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 po head
jego 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 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
zamiast kill
) spowoduje, że niektóre pociski będą milczały na temat tej śmierci (ale nadal zwrócą niezerowy status wyjścia).
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ą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ę [
.
...
? .
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.
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ż -m
go 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.