Menurut saya semua jawaban yang ada pada halaman ini salah, termasuk yang ditandai sebagai benar. Itu bermula dari fakta bahwa pertanyaan itu kata-kata yang ambigu.
Ringkasan: Jika Anda ingin menjalankan perintah "tepat sekali untuk setiap baris input yang diberikan," melewati seluruh baris (tanpa baris baru) ke perintah sebagai argumen tunggal, maka ini adalah cara terbaik yang kompatibel dengan UNIX untuk melakukannya:
... | tr '\n' '\0' | xargs -0 -n1 ...
GNU xargs
mungkin atau mungkin tidak memiliki ekstensi berguna yang memungkinkan Anda untuk menghapus tr
, tetapi mereka tidak tersedia pada OS X dan sistem UNIX lainnya.
Sekarang untuk penjelasan panjangnya ...
Ada dua masalah yang harus diperhatikan saat menggunakan xargs:
- bagaimana cara membagi input menjadi "argumen"; dan
- berapa banyak argumen untuk lulus perintah anak pada suatu waktu.
Untuk menguji perilaku xargs, kita memerlukan utilitas yang menunjukkan berapa kali dieksekusi dan dengan berapa banyak argumen. Saya tidak tahu apakah ada utilitas standar untuk melakukan itu, tetapi kita dapat mengkodekannya dengan mudah di bash:
#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo
Dengan asumsi Anda menyimpannya show
di direktori Anda saat ini dan membuatnya dapat dieksekusi, berikut ini cara kerjanya:
$ ./show one two 'three and four'
-> "one" "two" "three and four"
Sekarang, jika pertanyaan aslinya benar-benar tentang poin 2. di atas (seperti yang saya pikirkan, setelah membacanya beberapa kali) dan harus dibaca seperti ini (perubahan dicetak tebal):
Bagaimana saya bisa membuat xargs mengeksekusi perintah tepat sekali untuk setiap argumen input yang diberikan? Perilaku default-nya adalah memotong input menjadi argumen dan menjalankan perintah sesedikit mungkin , meneruskan beberapa argumen ke setiap instance.
maka jawabannya adalah -n 1
.
Mari kita bandingkan perilaku default xargs, yang membagi input sekitar whitespace dan memanggil perintah sesering mungkin:
$ echo one two 'three and four' | xargs ./show
-> "one" "two" "three" "and" "four"
dan perilakunya dengan -n 1
:
$ echo one two 'three and four' | xargs -n 1 ./show
-> "one"
-> "two"
-> "three"
-> "and"
-> "four"
Jika, di sisi lain, pertanyaan awal adalah tentang poin 1. input terpecah dan harus dibaca seperti ini (banyak orang yang datang ke sini tampaknya berpikir itulah masalahnya, atau membingungkan kedua masalah):
Bagaimana saya bisa membuat xargs menjalankan perintah dengan tepat satu argumen untuk setiap baris input yang diberikan? Perilaku standarnya adalah memotong garis di sekitar spasi putih .
maka jawabannya lebih halus.
Orang akan berpikir itu -L 1
bisa membantu, tetapi ternyata itu tidak mengubah parsing argumen. Itu hanya mengeksekusi perintah sekali untuk setiap baris input, dengan argumen sebanyak yang ada di baris input:
$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
Tidak hanya itu, tetapi jika garis berakhir dengan spasi, itu ditambahkan ke yang berikutnya:
$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"
Jelas, -L
ini bukan tentang mengubah cara xargs membagi input menjadi argumen.
Satu-satunya argumen yang melakukannya secara lintas platform (tidak termasuk ekstensi GNU) adalah -0
, yang membagi input di sekitar byte NUL.
Lalu, itu hanya masalah menerjemahkan baris baru ke NUL dengan bantuan tr
:
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"
Sekarang argumen parsing terlihat baik-baik saja, termasuk spasi spasi tambahan.
Akhirnya, jika Anda menggabungkan teknik ini dengan -n 1
, Anda mendapatkan tepat satu eksekusi perintah per baris input, input apa pun yang Anda miliki, yang mungkin merupakan cara lain untuk melihat pertanyaan asli (mungkin yang paling intuitif, diberi judul):
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show
-> "one "
-> "two"
-> "three and four"
find /path -type f -delete
akan lebih efisien :)