Menggunakan konektor setelah menemukan perintah

10

Saya ingin bash saya mencetak 'ditemukan' hanya jika sesuatu ditemukan, menggunakan perintah find. Tetapi menggunakan && tidak membantu: bahkan jika tidak menemukan apa pun, saya 'dicetak' dicetak. Contoh:

$ pwd
/data/data/com.termux/files/home/test/test1/test4
$ ls
xaa  xab
$ find . -name xac && echo 'found'
found
$ find . -name xaa && echo 'found'
./xaa
found
Josef Klimuk
sumber

Jawaban:

18

Anda dapat findmencetak sendiri found:

find . -name xac -printf "found\n" -quit

The -quitakan membuat find berhenti setelah pertandingan pertama , jadi foundhanya dicetak paling banyak sekali.

Pada utas serupa di Unix & Linux ( buat yang gagal ketika tidak ada yang ditemukan ), saya biasa grep -qzmengembalikan status keluar yang tidak nol jika findtidak menemukan apa pun:

find /some/path -print0 -quit | grep -qz .

Yang dapat Anda gunakan untuk membangun perintah majemuk menggunakan &&atau if:

find /some/path -print0 -quit | grep -qz . && echo found
muru
sumber
Saya harus menatap saat ini. /some/pathmemberitahu menemukan tempat untuk mulai mencari, tetapi tidak ada yang memberi tahu apa yang harus dicari. Sama dengan jawaban tertaut Anda. Apa yang berhasil bagi saya find /some/path -name xac -print0 -quit | grep -qz . && echo found? Apakah saya melewatkan sesuatu?
Joe
@Siapa yang penting di sini adalah -print0 -quit. Apa yang Anda masukkan sebelumnya tergantung pada apa yang ingin Anda temukan. Saya memilih untuk menghilangkan itu di sini.
muru
13

Jawaban muru sesuai dan cocok untuk kasus-kasus di mana kita ingin mencetak sesuatu jika file ditemukan. Untuk kasus umum ketika kita ingin mengeksekusi perintah eksternal, seperti echo, kita bisa menggunakan -execflag.

$ find . -name 'xac' -exec echo "I found " {} \; -quit             
I found  ./xac

Bagian {}meneruskan nama file ke perintah antara -execdan \;sebagai argumen. Catat \sebelum ;- ia mencegah shell dari salah mengartikannya ; di dalam koma penutupan shell menandakan akhir dari perintah, tetapi ketika lolos dengan slash, shell akan memperlakukannya sebagai teks literal untuk diteruskan ke findperintah dan untuk menemukan perintah itu berfungsi sebagai -execargumen penutup flag.


Untuk membangun kondisional if found do this; else do thatsemacam itu, kita dapat menggunakan substitusi perintah $()dan testperintah (alias [):

$ [ "x$(find . -name 'noexist' -print -quit)" != "x" ] && echo "found" || echo "not found"                                                                                              
not found

$ [ "x$(find . -name 'xac' -print -quit)" != "x" ] && echo "found" || echo "not found"                                                                                                  
found

Mengatasi komentar Dan

Dan di komentar bertanya:

Tidakkah gema "Saya menemukan {}" lebih baik daripada gema "Saya menemukan" {}? Mungkin untuk gema tidak masalah, tetapi jika seseorang menyalin perintah dan mengganti gema dengan perintah lain, mereka mungkin memiliki masalah

Mari kita pahami masalahnya dulu. Biasanya, dalam shell ada konsep pemisahan kata, yang berarti variabel yang tidak dikutip dan parameter posisi akan diperluas dan diperlakukan sebagai item terpisah. Misalnya, jika Anda memiliki variabel vardan itu berisi hello worldteks, ketika Anda melakukannya touch $varshell akan memecahnya menjadi dua item yang terpisah hellodan worlddan touchakan memahami bahwa seolah-olah Anda mencoba membuat 2 file terpisah; jika Anda melakukannya touch "$var", maka shell akan memperlakukan hello worldsebagai satu unit, dan touchakan membuat satu file saja. Ini penting untuk dipahami bahwa ini terjadi hanya karena cara kerja cangkang.

Sebaliknya, findtidak menderita perilaku seperti itu, karena perintah diproses dengan findsendirinya dan dieksekusi oleh execvp()system call, jadi tidak ada shell yang terlibat. Sementara kurung kurawal memang memiliki arti khusus dalam cangkang, karena mereka muncul di tengah-tengah findperintah, dan tidak pada awalnya, mereka tidak memiliki arti khusus untuk shell dalam kasus ini. Ini sebuah contoh. Mari kita membuat beberapa nama file yang sulit dan mencoba untuk memberikannya sebagai argumen untuk statperintah.

$ touch with$'\t'tab.txt with$' 'space.txt with$'\n'newline.txt

$ find -type f -exec stat -c "%F" {} \; -print                                                                                                                         
regular empty file
./with?newline.txt
regular empty file
./with space.txt
regular empty file
./with?tab.txt

Seperti yang Anda lihat, statmenerima nama file yang sulit dengan baik find, yang merupakan salah satu alasan utama mengapa dianjurkan untuk digunakan dalam skrip portabel, dan terutama berguna ketika Anda melintasi pohon direktori dan ingin melakukan sesuatu dengan nama file yang mungkin berpotensi memiliki karakter khusus di dalamnya. Oleh karena itu, tidak perlu mengutip kurung kurawal untuk perintah yang dieksekusi di find.

Ini adalah cerita yang berbeda ketika shell terlibat. Terkadang Anda perlu menggunakan shell untuk memproses nama file. Dalam hal itu, mengutip memang akan penting, tetapi penting untuk menyadari bahwa itu bukan masalah menemukan - itu adalah shell yang melakukan pemisahan kata.

$ find -type f -exec bash -c "stat {}" sh \;   
stat: cannot stat './with': No such file or directory
sh: line 1: newline.txt: command not found
stat: cannot stat './with': No such file or directory
stat: cannot stat 'space.txt': No such file or directory
stat: cannot stat './with': No such file or directory
stat: cannot stat 'tab.txt': No such file or directory

Jadi ketika kami mengutip dalam shell , itu akan berhasil. Tapi sekali lagi, itu penting untuk shell, bukan find.

$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;                                                                                                                 
regular empty file
regular empty file
regular empty file
Sergiy Kolodyazhnyy
sumber
Bukankah echo "I found {}"lebih baik dari itu echo "I found " {}? Mungkin untuk gema tidak masalah, tetapi jika seseorang menyalin perintah dan mengganti gema dengan perintah lain, mereka mungkin memiliki masalah.
Dan
@Dan topiknya terlalu panjang untuk dibahas dalam komentar, jadi saya mengedit jawaban saya. Silakan melihatnya
Sergiy Kolodyazhnyy
1
Terima kasih karena akhirnya membuat saya mengerti mengapa titik koma itu perlu ada di sana. Juga, penjelasan yang bagus tentang kutipan.
Joe
1
Tidak mengharapkan begitu banyak detail sebagai balasan atas komentar saya. Saya sangat menghargai penjelasan itu, terima kasih!
Dan