find -exec + vs find | xargs: mana yang harus dipilih?

32

Saya mengerti bahwa -execdapat mengambil +opsi untuk meniru perilaku xargs. Apakah ada situasi di mana Anda lebih suka satu formulir daripada yang lain?

Saya pribadi cenderung lebih suka bentuk pertama, jika hanya untuk menghindari menggunakan pipa. Saya pikir pasti para pengembang findpasti telah melakukan optimasi yang sesuai. Apakah saya benar?

rahmu
sumber

Jawaban:

21

Anda mungkin ingin membuat panggilan untuk menemukan (sekali, ketika Anda belajar, itu mungkin, yang mungkin hari ini). Ini, tentu saja, hanya mungkin selama Anda tetap menemukan. Setelah Anda melakukan pipe ke xargs, hal itu di luar jangkauan.

Contoh kecil, dua file a.lst dan b.lst:

cat a.lst
fuddel.sh
fiddel.sh

cat b.lst
fuddel.sh

Tidak ada trik di sini - hanya fakta bahwa keduanya mengandung "fuddel" tetapi hanya satu yang mengandung "fiddel".

Asumsikan kita tidak tahu itu. Kami mencari file yang sesuai dengan 2 ketentuan:

find -exec grep -q fuddel {} ";" -exec grep -q fiddel {} ";" -ls
192097    4 -rw-r--r--   1 stefan   stefan         20 Jun 27 17:05 ./a.lst

Yah, mungkin Anda tahu sintaks untuk grep atau program lain untuk melewatkan kedua string sebagai syarat, tapi bukan itu intinya. Setiap program yang dapat mengembalikan benar atau salah, diberikan file sebagai argumen, dapat digunakan di sini - grep hanyalah contoh yang populer.

Dan catatan, Anda dapat mengikuti menemukan exec dengan perintah find lainnya, seperti ls atau -delete atau yang serupa. Catatan, penghapusan itu tidak hanya rm (menghapus file), tetapi rmdir (menghapus direktori) juga.

Rantai seperti itu dibaca sebagai kombinasi AND dari perintah, selama tidak ditentukan (dengan -orswitch) (dan parens (yang perlu ditutup-tutupi)))).

Jadi Anda tidak meninggalkan rantai penemuan, yang merupakan hal yang berguna. Saya tidak melihat adanya keuntungan dalam menggunakan -xargs, karena Anda harus berhati-hati dalam mengirimkan file, yang merupakan sesuatu yang tidak perlu dilakukan - itu secara otomatis menangani melewati setiap file sebagai argumen tunggal untuk Anda.

Jika Anda yakin perlu beberapa penyembunyian untuk menemukan {} kawat gigi , jangan ragu untuk mengunjungi pertanyaan saya yang meminta bukti. Penegasan saya adalah: Anda tidak.

Pengguna tidak diketahui
sumber
3
Posting ini telah membuka mata saya tentang cara baru untuk menggunakan find. Terima kasih banyak!
rahmu
1
"Saya tidak melihat keuntungan dalam menggunakan -xargs". Apa -execcara melakukannya xargs -P4agar tiga dari empat core tidak tinggal diam?
Damian Yerrick
1
@DamianYerrick: Akhiri perintah -exec bukan di ";" tetapi dengan tanda + (/ plus).
pengguna tidak diketahui
25

Memanggil nama file dengan aman xargsmengharuskan Anda findmendukung -print0opsi dan Anda xargsmemiliki opsi yang sesuai untuk membacanya ( --nullatau -0). Jika tidak, nama file dengan karakter yang tidak diinginkan atau garis miring terbalik atau tanda kutip atau spasi putih dalam nama dapat menyebabkan perilaku yang tidak terduga. Di sisi lain, find -exec {} +ada dalam spesifikasi POSIXfind , sehingga portabel, dan ini seaman find -print0 | xargs -0, dan pasti lebih aman daripada find | xargs. Saya akan merekomendasikan tidak pernah melakukan find | xargstanpanya -print0.

jw013
sumber
6
Pengecualian penting untuk portabilitas find … -exec … {} +adalah OpenBSD, yang hanya memperoleh fitur ini dengan versi 5.1 yang dirilis pada 2012. Semua BSD telah memiliki -print0selama beberapa tahun, bahkan OpenBSD (meskipun ia menolak fitur itu untuk sementara waktu juga). Solaris, di sisi lain, menempel pada fitur POSIX, sehingga Anda dapat -exec +dan tidak -print0.
Gilles 'SO- berhenti bersikap jahat'
-print0adalah rasa sakit dan meskipun Anda bisa berdebat xargs --delimiter "\n"tidak setara, saya belum pernah menggunakan yang pertama setelah menemukan yang terakhir.
Sridhar Sarnobat
3
Saya tidak melihat bagaimana -0lebih menyakitkan daripada --delimiter "\n".
jw013
2
Selain itu -0, GNU xargsperlu -rmenghindari menjalankan perintah jika tidak ada input.
Stéphane Chazelas
2
Masalah lain | xargs -r0 cmdadalah cmdstdin yang terpengaruh (tergantung pada xargsimplementasinya, itu /dev/nullatau pipa.
Stéphane Chazelas
10

Jika Anda menggunakan -exec ... ;formulir (mengingat untuk keluar dari tanda titik koma), Anda menjalankan perintah sekali per nama file. Jika Anda menggunakan -print0 | xargs -0, Anda menjalankan beberapa perintah per nama file. Anda pasti harus menggunakan -exec +formulir, yang menempatkan banyak file dalam satu baris perintah dan jauh lebih cepat ketika sejumlah besar file terlibat.

Kelebihan menggunakan xargsadalah kemampuan untuk menjalankan beberapa perintah secara paralel menggunakan xargs -P. Pada sistem multi-core, itu dapat memberikan penghematan waktu yang sangat besar.

Alexios
sumber
6
Maksudmu, -Pbukannya -p. Perlu diingat xargs -Ptidak dalam standar POSIX, sedangkan find -exec {} +, yang penting jika Anda ingin portabilitas.
jw013
@Alexios Anda tidak perlu melarikan diri dari tanda plus, karena tidak memiliki arti khusus untuk shell: find /tmp/ -exec ls "{}" +berfungsi dengan baik.
daniel kullmann
1
Corrent, tentu saja. Saya telah melarikan diri dari semuanya setelah -execsekian lama (saya seorang masokis, saya bahkan tidak menggunakan tanda kutip untuk melarikan diri {}, saya selalu mengetik \{\}; jangan bertanya), semuanya sepertinya harus diloloskan sekarang.
Alexios
1
@Alexios: Jika Anda menemukan contoh (kecuali dari menjadi masokis) di mana penyembunyian kawat gigi berguna, berikan itu sebagai jawaban untuk pertanyaan saya di sini - afaik petunjuk ini sudah usang dan hanya berupa relik di halaman manual. Saya belum pernah melihat contoh di mana find /tmp/ -exec ls {} +tidak akan bekerja.
pengguna tidak diketahui
1
Bagi saya, ini adalah memori otot yang terbentuk pada zaman SunOS 4. Karena saya telah melakukannya selama bertahun-tahun, saya benar-benar gagal untuk memperhatikan ketika bashmulai menerima kawat gigi secara verbal. Saya cukup yakin setidaknya salah satu dari kerang tua yang saya gunakan cocok melemparkan hissy jika kawat gigi tidak lolos.
Alexios
8

Mengenai kinerja saya pikir itu -exec … + hanya akan lebih baik karena ini adalah alat tunggal yang melakukan semua pekerjaan tetapi bagian dari dokumentasi GNU findutil mengatakan bahwa -exec … +mungkin dalam beberapa kasus ini kurang efisien:

[temukan dengan -exec … +] bisa kurang efisien daripada beberapa penggunaan xargs; sebagai contohxargs memungkinkan baris perintah baru dibangun sementara perintah sebelumnya masih dijalankan, dan memungkinkan Anda menentukan sejumlah perintah untuk dijalankan secara paralel. Namun, find ... -exec ... +konstruksinya memiliki keunggulan portabilitas yang luas. GNU findutils tidak mendukung ' -exec ... +' sampai versi 4.2.12 [Januari 2005] ; salah satu alasan untuk ini adalah bahwa ia sudah memiliki tindakan ' -print0' dalam hal apa pun.

Saya tidak yakin apa artinya itu, jadi saya bertanya dalam obrolan di mana derobert menjelaskannya sebagai:

find mungkin dapat terus mencari kumpulan file selanjutnya sementara -exec … + sedang berjalan, tetapi tidak.
find … | xargs …tidak, karena kemudian menemukan adalah proses yang berbeda, dan terus berjalan sampai penyangga pipa terisi

(Memformat oleh saya.)

Jadi begitulah. Tetapi jika kinerja benar-benar penting, Anda harus melakukan benchmarking realistis atau bahkan bertanya pada diri sendiri apakah Anda bahkan ingin menggunakan shell untuk kasus tersebut.

Di sini, di situs ini saya pikir lebih baik menyarankan orang untuk menggunakan -exec … +formulir kapan pun dimungkinkan karena hanya karena lebih sederhana dan untuk alasan yang disebutkan dalam jawaban lain di sini (misalnya menangani nama file aneh tanpa harus berpikir banyak).

phk
sumber