temukan -exec cmd {} + vs | xargs

115

Manakah yang lebih efisien untuk kumpulan file yang sangat besar dan harus digunakan?

find . -exec cmd {} +

atau

find . | xargs cmd

(Asumsikan bahwa tidak ada karakter lucu di nama file)

dogbane
sumber
Terkait: stackoverflow.com/questions/9612090/…
Mateusz Piotrowski

Jawaban:

107

Perbedaan kecepatan tidak akan signifikan.

Tetapi Anda harus memastikan bahwa:

  1. Skrip Anda tidak akan menganggap bahwa tidak ada file yang memiliki spasi, tab, dll dalam nama file; versi pertama aman, yang kedua tidak.

  2. Skrip Anda tidak akan memperlakukan file yang dimulai dengan " -" sebagai opsi.

Jadi kode Anda akan terlihat seperti ini:

find . -exec cmd -option1 -option2 -- {} +

atau

find . -print0 | xargs -0 cmd -option1 -option2 --

Versi pertama lebih pendek dan lebih mudah untuk ditulis karena Anda dapat mengabaikan 1, tetapi versi kedua lebih portabel dan aman, karena " -exec cmd {} +" adalah opsi yang relatif baru di GNU findutils (sejak 2005, banyak sistem yang sedang berjalan belum memilikinya) dan itu buggy baru-baru ini . Juga banyak orang tidak mengetahui " -exec cmd {} +" ini, seperti yang Anda lihat dari jawaban lain.

Tometzky
sumber
4
-print0 juga merupakan opsi GNU find (dan GNU xargs) yang hilang dari banyak sistem non-Linux, sehingga argumen portabilitas tidak valid. Hanya menggunakan -print dan meninggalkan -0 off dari xargs, bagaimanapun, adalah sangat portabel.
dannysauer
7
Intinya adalah tanpa -print0 itu tidak berfungsi jika ada file dengan spasi atau tab dll. Ini bisa menjadi kerentanan keamanan seolah-olah ada nama file seperti "foo -o index.html" maka -o akan diperlakukan sebagai pilihan. Coba di direktori kosong: "touch - foo \ -o \ index.html; find. | Xargs cat". Anda akan mendapatkan: "cat: opsi tidak valid - 'o'"
Tometzky
2
Contohnya adalah nama file yang berisi -. Tanpa -print0, find akan mengeluarkan ./foo -o index.html. Jadi mungkin memulai dengan - bukan masalah besar, tetapi hasilnya sedikit berubah, dan pada sistem multipengguna, dapat menyediakan vektor serangan jika skrip Anda dapat dibaca di seluruh dunia.
bobpaul
2
Sebuah catatan tentang sesuatu yang membuat saya tersandung di sini - menggunakan execakan menampilkan hasil seperti yang ditemukan, sedangkan xargstampaknya, menunggu sampai seluruh direktori dicari sebelum menulis ke stdout. Jika Anda mencoba ini pada direktori besar, dan tampaknya itu xargstidak berhasil, kesabaran disarankan.
FarmerGedden
1
@Motivated Without -print0find mengembalikan nama file yang dipisahkan dengan baris baru, tetapi baris baru juga bisa menjadi bagian dari nama file, membuatnya ambigu. Byte 0 tidak bisa, jadi ini adalah pemisah yang aman. Ya - menambahkan --ke perintah yang mendukungnya adalah praktik yang baik ketika Anda tidak dapat mengontrol argumennya, meskipun tidak selalu diperlukan atau tidak aman.
Tometzky
7
find . | xargs cmd

lebih efisien (berjalan cmdsesedikit mungkin, tidak seperti exec, yang berjalan cmdsekali untuk setiap pertandingan). Namun, Anda akan mengalami masalah jika nama file mengandung spasi atau karakter yang funky.

Berikut ini disarankan untuk digunakan:

find . -print0 | xargs -0 cmd

ini akan bekerja bahkan jika nama file berisi karakter funky ( -print0merek findmencetak pertandingan NUL-dihentikan, -0merek xargsberharap format ini.)

Meminta
sumber
28
Ini bukan "find. -Exec cmd {} \;" tetapi "temukan. -exec cmd {} +". Yang terakhir tidak akan menjalankan file satu per satu.
Tometzky
2
Perhatikan bahwa xargspendekatan ini sebenarnya jauh lebih lambat jika tidak ada (atau hanya beberapa) file yang cocok dan cmdtidak banyak yang harus dilakukan untuk setiap file. Misalnya, ketika dijalankan di direktori kosong, xargsversi akan memakan waktu setidaknya dua kali lipat, karena dua proses harus dimulai, bukan hanya satu. (Ya, perbedaannya biasanya tidak terlihat di * nix, tetapi dalam satu lingkaran itu mungkin penting; atau, coba di Windows beberapa saat ...)
SamB
2

xargsVersi modern sering kali mendukung eksekusi pipeline paralel.

Jelas ini mungkin menjadi titik pivot dalam hal pilihan antara find … -exec dan … | xargs

poige
sumber