Bagaimana cara menghentikan perintah find setelah pertandingan pertama?

131

Apakah ada cara untuk memaksa findperintah berhenti tepat setelah menemukan pertandingan pertama?

coffeMug
sumber
4
TheUnseen: Alasan mengapa ia berhenti setelah lima hasil saat disalurkan ke kepala -n 5 adalah karena kepala keluar setelah lima hasil. Ketika head keluar, pipa menutup dan mengirimkan sinyal ke program, yang akan diputus juga. Maaf karena tidak merespons langsung kepada Anda, tampaknya Anda perlu 50 reputasi untuk membalas.
Ruste

Jawaban:

148

Dengan GNU atau FreeBSD find, Anda dapat menggunakan -quitpredikat:

find . ... -print -quit

findSetara dengan NetBSD :

find . ... -print -exit

Jika semua yang Anda lakukan adalah mencetak nama, dan dengan asumsi nama file tidak mengandung karakter baris baru, Anda bisa melakukannya:

find . ... -print | head -n 1

Itu tidak akan berhenti findsetelah pertandingan pertama, tetapi mungkin, tergantung pada waktu dan buffering pada pertandingan kedua atau (banyak) nanti. Pada dasarnya, findakan diakhiri dengan SIGPIPE ketika mencoba mengeluarkan sesuatu saat headsudah tidak ada karena sudah membaca dan menampilkan baris input pertama.

Perhatikan bahwa tidak semua shell akan menunggu findperintah itu setelah headkembali. Shell Bourne dan implementasi AT&T ksh(ketika non-interaktif) dan yash(hanya jika pipa itu adalah perintah terakhir dalam sebuah skrip) tidak akan, membiarkannya berjalan di latar belakang. Jika Anda lebih suka melihat perilaku itu di shell apa pun, Anda selalu bisa mengubah hal di atas menjadi:

(find . ... -print &) | head -n 1

Jika Anda melakukan lebih dari sekadar mencetak jalur file yang ditemukan, Anda dapat mencoba pendekatan ini:

find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;

(ganti printfdengan apa pun yang Anda lakukan dengan file itu).

Itu memiliki efek samping findmengembalikan status keluar yang mencerminkan fakta bahwa itu dibunuh.

Sebenarnya, menggunakan sinyal SIGPIPE dan bukannya SIGTERM ( kill -s PIPEbukan kill) akan menyebabkan beberapa shell menjadi lebih diam tentang kematian itu (tetapi masih akan mengembalikan status keluar yang tidak nol).

Stéphane Chazelas
sumber
3
Kalau-kalau ada yang perlu menguji apakah ada file yang cocok dengan predikat, berhenti segera setelah ditemukan, di Bash dan GNU Find yang dapat Anda lakukan: if [[ $(find ... -print -quit) ]]; then ...Ini hanya menguji apakah menemukan sesuatu yang dicetak sama sekali.
Tobia
@Tobia Lebih baik untuk memasukkan $(…)bagian dalam tanda kutip jika Anda hanya menggunakan tanda kurung tunggal ( [ … ]).
phk
@ phk Kecuali saya tidak menggunakan tanda kurung tunggal (karena mereka mengerikan) jadi saya tidak perlu menggunakan tanda kutip.
Tobia
2
@Tobia, [adalah perintah standar. Ini bukan perintah yang mengerikan tapi cara Bourne-like shells mengurai baris perintah. [[...]]adalah konstruksi ksh yang memiliki masalah sendiri dalam berbagai shell. Misalnya, hingga saat [[ $(...) ]]ini tidak akan berfungsi zsh(Anda perlu [[ -n $(...) ]]). Kecuali di zsh, Anda memerlukan tanda kutip di [[ $a = $b ]], [[ =~ ]]memiliki perbedaan yang tidak kompatibel antara implementasi dan bahkan antara versi untuk bash dan beberapa bug di beberapa. Secara pribadi, saya lebih suka [.
Stéphane Chazelas
apa ...? .
kyb
11
find . -name something -print -quit

Menghentikan pencarian setelah pertandingan pertama setelah mencetaknya.

Hentikan pencarian setelah sejumlah yang cocok dan hasil cetak:

find . -name something -print | head -n 5

Cukup mengejutkan - kepala sekarang mengakhiri string setelah 5 pertandingan, meskipun saya tidak tahu bagaimana atau mengapa.

Sangat mudah untuk diuji. Hanya membiarkan menemukan mencari sebuah di akar yang akan menghasilkan ribuan, bahkan mungkin lebih banyak pertandingan saat mengambil setidaknya satu menit atau lebih. Tetapi ketika disalurkan ke "head" "find" akan berakhir setelah jumlah baris yang ditentukan didefinisikan dalam head (head default menunjukkan 10, gunakan "head -n" untuk menentukan baris).

Perhatikan bahwa ini akan berakhir setelah "head -n" mencapai jumlah karakter baris baru yang ditentukan dan karenanya setiap kecocokan yang berisi beberapa karakter baris baru akan dihitung sesuai.

TheUnseen
sumber
Saya juga mengamati ini 'program berakhir setelah kepala selesai dengan outputnya', tetapi tidak secara konsisten di shell. Saya pikir ini pantas pertanyaannya sendiri - untungnya untuk bash jawabannya sudah ada di Bash: Head & Tail perilaku StackOverflow dengan skrip bash . Itu memberikan informasi yang cukup bagi saya untuk menyimpulkan bahwa apakah program berakhir atau terus dijalankan di latar belakang tergantung pada tanggapannya terhadap SIGPIPE - membunuh adalah default.
bijak
Saya bermaksud 'lintas * program * / kerang', tetapi tampaknya unix.stackexchange.com lebih suka bahwa saya mencatat ini sebagai komentar kedua daripada membiarkan saya mengedit komentar pertama saya (ini adalah stackexchange, keputusan kebijakan khusus situs). Juga, saya sekarang melihat bahwa @Ruste mengomentari efek ini di bagian atas, yang pada awalnya tidak membantu saya karena saya langsung menjawab ...
bijak
2

Untuk tujuan hiburan, inilah generator pencari malas di Bash. Contoh ini menghasilkan cincin di atas file di direktori saat ini. Bacalah sebanyak yang Anda inginkan kill %+(mungkin hanya 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
sumber
1

grep juga kembali jika digunakan dengan flag -m, begitu juga dengan

find stuff | grep -m1 .

itu akan kembali setelah baris pertama dicetak oleh find.

Perbedaan antara ini dan find stuff -print -quit | head -1adalah bahwa jika pencarian grep cukup cepat mungkin tidak dapat menghentikan proses dalam waktu (tidak terlalu penting meskipun), sedangkan jika pencarian panjang itu akan menghemat menemukan untuk mencetak banyak yang tidak diperlukan garis.

ini malah berfungsi dengan busybox find, walaupun karena busybox grep juga memilikinya -mtidak terlalu diperlukan

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

ini akan memuntahkan pesan tentang proses find setelah menerima sinyal sigterm (biasanya), tetapi output ini milik shell yang sedang berjalan, bukan perintah find sehingga tidak mengacaukan dengan output perintah, artinya pipa atau pengalihan akan menampilkan hanya baris cocok dengan find.

belum dibuka
sumber