C'è un modo per forzare l' find
arresto del comando subito dopo aver trovato la prima partita?
C'è un modo per forzare l' find
arresto del comando subito dopo aver trovato la prima partita?
Risposte:
Con GNU o FreeBSD find
, puoi usare il -quit
predicato:
find . ... -print -quit
L' find
equivalente NetBSD :
find . ... -print -exit
Se tutto ciò che fai è stampare il nome e supponendo che i nomi dei file non contengano caratteri di nuova riga, potresti fare:
find . ... -print | head -n 1
Ciò non si interromperà find
dopo la prima partita, ma probabilmente, a seconda dei tempi e del buffering della seconda partita o (molto) in seguito. Fondamentalmente, find
verrà terminato con un SIGPIPE quando tenta di emettere qualcosa mentre head
è già sparito perché ha già letto e visualizzato la prima riga di input.
Nota che non tutte le shell aspetteranno quel find
comando dopo che head
è tornato. Le implementazioni della shell Bourne e AT&T di ksh
(quando non interattive) e yash
(solo se quella pipeline è l'ultimo comando in uno script) non lo farebbero, lasciandola in esecuzione in background. Se preferisci vedere quel comportamento in qualsiasi shell, puoi sempre cambiare quanto sopra in:
(find . ... -print &) | head -n 1
Se stai facendo qualcosa di più della stampa dei percorsi dei file trovati, potresti provare questo approccio:
find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;
(sostituiscilo printf
con qualunque cosa faresti con quel file).
Ciò ha l'effetto collaterale di find
restituire uno stato di uscita che riflette il fatto che è stato ucciso.
In realtà, l'uso del segnale SIGPIPE invece di SIGTERM ( kill -s PIPE
anziché kill
) farà sì che alcune shell rimangano più silenziose su quella morte (ma restituirebbero comunque uno stato di uscita diverso da zero).
if [[ $(find ... -print -quit) ]]; then ...
Verifica semplicemente se trova qualcosa stampato.
$(…)
parte tra virgolette nel caso in cui si utilizzino solo le parentesi singole ( [ … ]
).
[
è un comando standard. Non è tanto orribile quel comando, ma il modo in cui le conchiglie tipo Bourne analizzano le linee di comando. [[...]]
è un costrutto ksh che ha problemi propri in varie shell. Ad esempio, fino a poco tempo fa [[ $(...) ]]
non funzionava zsh
(necessario [[ -n $(...) ]]
). Tranne in zsh
, hai bisogno di virgolette [[ $a = $b ]]
, le [[ =~ ]]
differenze sono incompatibili tra le implementazioni e persino tra le versioni per bash e alcuni bug in alcuni. Personalmente, preferisco [
.
...
? .
find . -name something -print -quit
Termina la ricerca dopo la prima corrispondenza dopo averla stampata.
Termina la ricerca dopo un determinato numero di corrispondenze e stampa i risultati:
find . -name something -print | head -n 5
Abbastanza sorprendentemente, la testa ora termina la stringa dopo 5 partite, anche se non so come o perché.
È molto facile da testare. Basta trovare la ricerca a su root che porterebbe a migliaia, forse anche più corrispondenze impiegando almeno un minuto o più. Ma quando convogliato in "head" "find" termina dopo la quantità specificata di righe definite in head (default head mostra 10, usa "head -n" per specificare le righe).
Si noti che ciò terminerà dopo che "head -n" avrà raggiunto il conteggio dei caratteri di nuova riga specificato e pertanto qualsiasi corrispondenza che contiene più caratteri di nuova riga verrà conteggiata di conseguenza.
A scopo di intrattenimento, ecco un generatore di ricerca pigro in Bash. Questo esempio genera un anello sui file nella directory corrente. Leggi quanti ne vuoi allora kill %+
(forse solo 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 ritorna anche se usato con la bandiera -m
, quindi con
find stuff | grep -m1 .
tornerà dopo la prima riga stampata da find.
La differenza tra questo ed find stuff -print -quit | head -1
è che se la ricerca è abbastanza veloce grep potrebbe non essere in grado di arrestare il processo in tempo (non importa davvero però), mentre se la ricerca è lunga risparmierà di stampare molto non necessario Linee.
questo invece funziona con la ricerca di busybox, anche se dal momento che busybox grep ha anche -m
non è davvero necessario
find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;
questo sputerà un messaggio sul processo find che ha ricevuto il segnale (di solito) sigterm, ma questo output appartiene alla shell in esecuzione, non al comando find, quindi non confonde con l'output del comando, il che significa che pipe o reindirizzamenti produrranno solo la linea abbinato da trova.