Kapan `menemukan. -exec PERINTAH {} + `jalankan PERINTAH beberapa kali?

8

Jika aku melakukan

find . -exec echo {} +

itu mencetak semua jalur dalam satu baris, yaitu perintah echohanya dijalankan sekali.

Namun menurut man find,

-exec command {} +
    ... the number of invocations of the command will 
be much  less  than  the  number  of matched files. ...

Tampaknya dalam beberapa keadaan perintah akan dieksekusi beberapa kali. Apakah saya benar? Mohon dicontohkan.

beku-api
sumber

Jawaban:

7

POSIX find -exec utility_name [argumen ...] {} + didefinisikan sebagai:

Akhir dari ekspresi primer harus diberi tanda baca oleh <semicolon> atau dengan <plus-sign>. Hanya <plus-sign> yang segera mengikuti argumen yang hanya berisi dua karakter "{}" yang akan menandai akhir dari ekspresi utama. Penggunaan lain dari <plus-sign> tidak akan diperlakukan sebagai khusus. Jika ekspresi primer diselingi oleh <semicolon>, utilitas utility_name harus dipanggil sekali untuk setiap pathname dan primer akan mengevaluasi sebagai true jika utilitas mengembalikan nilai nol sebagai status keluar. Sebuah utility_name atau argumen yang hanya berisi dua karakter "{}" harus diganti dengan nama path saat ini. Jika sebuah utility_name atau argumenstring berisi dua karakter "{}", tetapi tidak hanya dua karakter "{}", itu adalah implementasi yang ditentukan apakah menemukan menggantikan dua karakter atau menggunakan string tanpa perubahan.

Jika ekspresi primer diselingi oleh <plus-sign>, primer harus selalu dievaluasi sebagai benar, dan nama path yang dievaluasi primer akan diagregasi ke dalam set. Utilitas utility_name harus dipanggil sekali untuk setiap set nama path yang digabungkan. Setiap doa harus dimulai setelah pathname terakhir di set dikumpulkan, dan harus diselesaikan sebelum utilitas find keluar dan sebelum pathname pertama di set berikutnya (jika ada) dikumpulkan untuk primer ini, tetapi dinyatakan tidak ditentukan apakah permintaan terjadi sebelum, selama, atau setelah evaluasi pendahuluan lainnya. Jika ada permintaan mengembalikan nilai bukan nol sebagai status keluar, temukan utilitas akan mengembalikan status keluar yang tidak nol. Argumen yang hanya berisi dua karakter "{}" harus diganti dengan sekumpulan nama path teragregasi, dengan masing-masing nama path dilewatkan sebagai argumen terpisah ke utilitas yang dipanggil dalam urutan yang sama seperti yang digabungkan. Ukuran setiap kumpulan dua atau lebih nama path harus dibatasi sedemikian rupa sehingga pelaksanaan utilitas tidak menyebabkan batas {ARG_MAX} sistem terlampaui . Jika ada lebih dari satu argumen yang mengandung dua karakter "{}", perilaku tersebut tidak ditentukan.

Ketika set panjang nama file yang Anda temukan melebihi sistem ARG_MAX, perintah dieksekusi.

Anda bisa ARG_MAXmenggunakan getconf :

$ getconf ARG_MAX
2097152

Pada beberapa sistem, nilai aktual ARG_MAXdapat berbeda, Anda dapat merujuk di sini untuk detail lebih lanjut.

cuonglm
sumber
Saya menjalankan percobaan menggunakan find / -exec echo | wcdan mengukur rasio antara jumlah karakter dan jumlah baris. Saya menemukan bahwa panjang baris perintah maksimum yang digunakan findsecara signifikan lebih kecil daripada batas POSIX teoretis, dan jauh lebih dekat dengan Size of command buffer we are actually usinggaris dalam output dari xargs --show-limits. Ini berlaku untuk Linux dan mungkin juga berlaku untuk implementasi Mac OS find, meskipun xargstidak akan mencetak nilai di Mac OS. Adakah yang tahu mengapa ini terjadi?
pqnet
--show-limitstidak ditentukan oleh POSIX, implementasi Mac OS xargstidak mendukungnya. find / -exec echo | wctidak akan bekerja Ingatlah bahwa ARG_MAXkembalikan byte. Dan itu panjang maksimal dari argumen ke exec(3)fungsi.
cuonglm
Saya tahu --show-limitsbukan POSIX, meskipun ini bukan panjang argumen maksimum yang digunakan find, yang menggunakan nilai lebih kecil. Saya tidak mengerti mengapa Anda mengatakan itu find / -exec echo | wctidak akan berhasil: menurut saya itu adalah cara yang baik untuk memiliki perkiraan nilai riil (dan dari apa yang bisa saya lihat, lebih baik daripada menggunakan getconf ARG_MAX). Juga, filesystem saya kebanyakan jika tidak semua karakter ASCII, jadi jumlah karakter kira-kira sama dengan jumlah byte.
pqnet
@ pqnet: gunakan find / -exec sh -c 'echo $@ | wc -c' _ {} +isntead.
cuonglm
maaf saya salah menulis, saya benar-benar menggunakanfind / -exec echo {} + | wc -lc
pqnet
7

Ada panjang maksimum daftar argumen untuk proses baru dalam sistem POSIX. findakan membagi eksekusi jika path file lebih panjang dari ini. Untuk melihat batasan di Linux, gunakan xargs --show-limits(jangan bekerja di Mac OS, jika seseorang tahu alternatif yang lebih baik, silakan komentar di sini)

sunting: dicuri langsung dari jawaban Gnouc, cara POSIX untuk mendapatkan panjang maksimum daftar argumen adalah getconf ARG_MAX. Namun, saya menjalankan percobaan pada mesin mac os saya, dan sepertinya findmenggunakan sedikit lebih dari setengah angka itu. Ini koheren dengan fakta bahwa, pada sistem di mana ia bekerja, xargs --show-limitsmemberitahu kita bahwa itu tidak akan menggunakan panjang argumen maksimum (dalam hal ini juga akan menggunakan sekitar setengah angka itu), namun saya tidak dapat menemukan penjelasan untuk itu.

sunting 2: tampaknya satu-satunya cara yang dapat diandalkan untuk menentukan berapa banyak parameter findakan tetap bersatu untuk setiap doa adalah dengan bereksperimen, misalnya dengan menjalankan

find / -exec echo {} + | wc -cl

Karena output dari findmemiliki garis untuk setiap echodoa, dimungkinkan untuk menghitungnya menggunakan wc -l. Jumlah total byte echoed adalah output dari wc -cgantinya. Membagi satu dengan yang lain Anda mendapatkan jumlah rata-rata byte dalam parameter untuk setiap permintaan perintah (meskipun nilai yang sedikit lebih rendah, karena pembulatan, kira-kira setengah dari rata-rata panjang lintasan di sistem Anda)

pqnet
sumber
xargstidak menggunakan panjang argumen maksimum penuh karena banyak program menambahkan beberapa argumen tambahan dan kemudian meneruskan argumen ke program lain. Jika xargsmengisi argumen hingga batas maksimum absolut, program seperti itu rusak, karena tidak akan ada ruang untuk argumen tambahan itu.
hvd
@ DVD masuk akal. Tetapi kemudian, adakah cara POSIX untuk mengetahui berapa banyak buffer yang digunakan oleh xargsatau find?
pqnet
Anda dapat mengeksekusinya dengan daftar argumen yang sangat panjang, menentukan berapa banyak argumen yang dilewatkan dalam doa pertama (sesuatu seperti yes . | xargs | head -n 1 | wc -c) dan membandingkannya dengan output dari getconf ARG_MAX. Tapi, sebenarnya mencobanya di sistem saya, saya mendapatkan perbedaan yang sangat besar sehingga sepertinya ada yang lebih dari yang saya sadari.
hvd
jadi intinya untuk bereksperimen ... Saya akan memperbarui jawaban saya
pqnet