cat a.txt | xargs -I % echo %
Pada contoh di atas, xargs digunakan echo %
sebagai argumen perintah. Tetapi dalam beberapa kasus, saya perlu beberapa perintah untuk memproses argumen, bukan satu. Sebagai contoh:
cat a.txt | xargs -I % {command1; command2; ... }
Tetapi xargs tidak menerima formulir ini. Satu solusi yang saya tahu adalah saya bisa mendefinisikan fungsi untuk membungkus perintah, tapi itu bukan pipa, saya tidak suka itu. Apakah ada solusi lain?
while
loop yang dapat berisi banyak perintah.Jawaban:
... atau, tanpa Penggunaan Kucing yang Tidak Berguna :
Untuk menjelaskan beberapa poin penting:
Penggunaan
"$arg"
bukannya%
(dan tidak adanya-I
dalamxargs
baris perintah) adalah untuk alasan keamanan: Melewatkan data padash
daftar argumen baris perintah alih-alih menggantikannya ke dalam kode mencegah konten yang mungkin berisi data (seperti$(rm -rf ~)
, untuk mengambil khususnya malicious example) agar tidak dieksekusi sebagai kode.Demikian pula, penggunaan
-d $'\n'
adalah ekstensi GNU yang menyebabkanxargs
memperlakukan setiap baris dari file input sebagai item data yang terpisah. Entah ini atau-0
(yang mengharapkan NUL alih-alih baris baru) diperlukan untuk mencegah xargs mencoba menerapkan shell-like (tapi tidak kompatibel dengan shell) untuk menguraikan aliran yang dibacanya. (Jika Anda tidak memiliki GNU xargs, Anda dapat menggunakantr '\n' '\0' <a.txt | xargs -0 ...
untuk mendapatkan bacaan berorientasi baris tanpa-d
)The
_
adalah pengganti untuk$0
, sehingga nilai-nilai data lainnya ditambahxargs
menjadi$1
dan seterusnya, yang terjadi menjadi default set nilai-nilaifor
lingkaran iterates atas.sumber
sh -c
- perhatikan bahwa tanda koma setelah setiap perintah tidak opsional, bahkan jika itu adalah perintah terakhir dalam daftar.command1
dancommand2
; Saya kemudian menyadari bahwa itu tidak perlu.}
:sh -c '{ command1; command2; }' -- but it's not required at the end of a command sequence that doesn't use braces:
sh -c 'command1; command2'`%
karakter di suatu tempat di string yang diteruskan ke Andash -c
, maka ini rentan terhadap kerentanan keamanan: Sebuah nama file yang mengandung$(rm -rf ~)'$(rm -rf ~)'
(dan itu adalah substring yang sah untuk dimiliki dalam nama file pada sistem file UNIX yang umum!) Akan menyebabkan seseorang pada hari yang sangat buruk .Dengan GNU Parallel Anda dapat melakukan:
Tonton video intro untuk mempelajari lebih lanjut: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
Untuk alasan keamanan disarankan Anda menggunakan manajer paket Anda untuk menginstal. Tetapi jika Anda tidak dapat melakukannya maka Anda dapat menggunakan instalasi 10 detik ini.
Instalasi 10 detik akan mencoba melakukan instalasi penuh; jika itu gagal, instalasi pribadi; jika itu gagal, instalasi minimal.
sumber
Ini hanyalah pendekatan lain tanpa xargs atau kucing:
sumber
IFS
, itu akan mengabaikan spasi putih memimpin dan tertinggal di nama file; kecuali Anda menambahkan-r
, nama file dengan garis miring terbalik literal akan mengabaikan karakter tersebut.xargs
. (Ini sulit diperluas untuk melakukan sesuatu yang mirip dengan opsi GNUxargs
'-P<n>
)$ command | while read line; do c1 $line; c2 $line; done
Kamu bisa memakai
{} = variabel untuk setiap baris pada file teks
sumber
file.txt
berisi datum dengan$(rm -rf ~)
sebagai substring?Satu hal yang saya lakukan adalah menambahkan .bashrc / .profile fungsi ini:
maka Anda dapat melakukan hal-hal seperti
yang kurang verbose dari xargs atau -exec. Anda juga dapat memodifikasi fungsi untuk menyisipkan nilai dari pembacaan di lokasi arbitrer pada perintah untuk masing-masing, jika Anda memerlukan perilaku itu juga.
sumber
Saya lebih suka gaya yang memungkinkan mode lari kering (tanpa
| sh
):Bekerja dengan pipa juga:
sumber
-P
option ... (Jika tidak, aku lebih sering menggunakan-exec
padafind
, karena masukan saya sebagian besar nama file)Sedikit terlambat ke pesta.
Saya menggunakan format di bawah ini untuk mengompresi direktori saya dengan ribuan file kecil sebelum bermigrasi. Jika Anda tidak membutuhkan tanda kutip tunggal di dalam perintah, itu harus berfungsi.
Dengan beberapa modifikasi, saya yakin itu akan bermanfaat bagi seseorang. Diuji dalam
Cygwin
(babun)find .
Temukan di sini-maxdepth 1
Jangan masuk ke direktori anak-anak! -path .
Kecualikan. / Jalur direktori saat ini-type d
hanya cocok dengan direktori-print0
Pisahkan output dengan byte nol \ 0| xargs
Pipa ke xargs-0
Input null dipisahkan byte-I @@
Placeholder adalah @@. Ganti @@ dengan input.bash -c '...'
Jalankan perintah Bash,{...}
Pengelompokan perintah&&
Jalankan perintah berikutnya hanya jika perintah sebelumnya berhasil keluar (keluar 0)Terakhir
;
itu penting, kalau tidak maka akan gagal.Keluaran:
Pembaruan 2018 Juli:
Jika Anda suka hack dan bermain-main, berikut ini sesuatu yang menarik:
Keluaran:
Penjelasan:
- Membuat skrip satu liner dan menyimpannya dalam variabel
-
xargs
membacaa.txt
dan mengeksekusinya sebagaibash
skrip-
@@
memastikan setiap kali seluruh baris dilewati- Menempatkan
@@
setelah--
memastikan@@
diambil sebagai input parameter posisi kebash
perintah, bukanbash
memulaiOPTION
, yaitu seperti-c
itu sendiri artinyarun command
--
ajaib, ia bekerja dengan banyak hal lain, yaitussh
, bahkankubectl
sumber
find . -type f -print0|xargs -r0 -n1 -P20 bash -c 'f="{}";ls -l "$f"; gzip -9 "$f"; ls -l "$f.gz"'
(Ini sedikit lebih mudah ketika mengkonversi loop)"$@"
adalah satu-satunya cara untuk menghindari itu ... (dengan-n1
jika Anda ingin membatasi jumlah parameter))--
digunakan oleh shell untuk mengatakan bahwa tidak ada lagi opsi yang dapat diterima. Ini memungkinkan ada-
after after--
juga. Anda bisa mendapatkan hasil yang sangat menarik dan membingungkan jika Anda tidak melakukannya misalnyagrep -r
ketika Anda memasukkan dalam pola-
! Cara Anda mengucapkannya tidak menjelaskan ini tidak benar-benar menjelaskan cara kerjanya. Iirc itu adalah hal POSIX tetapi bagaimanapun juga itu layak menunjukkan ini, saya pikir. Hanya sesuatu yang perlu dipertimbangkan. Dan saya suka sekali bonus itu!Ini sepertinya versi yang paling aman.
(
-0
dapat dihapus dantr
diganti dengan redirect (atau file dapat diganti dengan file yang dipisahkan nol sebagai gantinya). Hal ini terutama di sana karena saya terutama menggunakanxargs
denganfind
dengan-print0
output) (Ini mungkin juga relevan padaxargs
versi tanpa-0
ekstensi)Aman, karena args akan meneruskan parameter ke shell sebagai larik ketika mengeksekusinya. Shell (setidaknya
bash
) akan meneruskannya sebagai array yang tidak diubah ke proses lain ketika semua diperoleh dengan menggunakan["$@"][1]
Jika Anda menggunakan
...| xargs -r0 -I{} bash -c 'f="{}"; command "$f";' ''
, tugas akan gagal jika string berisi tanda kutip ganda. Ini berlaku untuk setiap varian yang menggunakan-i
atau-I
. (Karena itu diganti menjadi string, Anda selalu dapat menyuntikkan perintah dengan memasukkan karakter yang tidak terduga (seperti tanda kutip, tanda kutip atau tanda dolar) ke dalam data input)Jika perintah hanya dapat mengambil satu parameter sekaligus:
Atau dengan proses yang agak kurang:
Jika Anda memiliki GNU
xargs
atau yang lain dengan-P
ekstensi dan Anda ingin menjalankan 32 proses secara paralel, masing-masing dengan tidak lebih dari 10 parameter untuk setiap perintah:Ini harus kuat terhadap karakter khusus apa pun dalam input. (Jika inputnya dipisahkan nol).
tr
Versi ini akan mendapatkan beberapa input yang tidak valid jika beberapa baris berisi baris baru, tetapi itu tidak dapat dihindari dengan file yang dipisahkan baris baru.Parameter kosong pertama
bash -c
adalah karena ini: (Daribash
halaman manual ) (Terima kasih @clacke)sumber
"$@"
bash -c 'command1 "$@"; command2 "$@";' arbitrarytextgoeshere
bash
Dengan-c
mengambil pertama (setelah perintah) satu argumen yang akan menjadi nama proses, maka dibutuhkan argumen posisi. Cobabash -c 'echo "$@" ' 1 2 3 4
dan lihat apa yang keluar.Solusi lain yang mungkin bekerja bagi saya adalah sesuatu seperti -
Catat 'bash' di akhir - saya berasumsi ini dilewatkan sebagai argv [0] ke bash. Tanpa itu dalam sintaks ini parameter pertama untuk setiap perintah hilang. Mungkin kata apa saja.
Contoh:
sumber
"$@"
, maka Anda membelah string dan memperluas daftar argumen.BKM saya saat ini untuk ini
Sangat disayangkan bahwa ini menggunakan perl, yang lebih kecil kemungkinannya untuk diinstal daripada bash; tetapi menangani lebih banyak input dari jawaban yang diterima. (Saya menyambut versi mana-mana yang tidak bergantung pada perl.)
@ Saran KeithThompson tentang
hebat - kecuali jika Anda memiliki karakter komentar shell # di input Anda, yang mana bagian dari perintah pertama dan semua perintah kedua akan terpotong.
Hash # bisa sangat umum, jika input berasal dari daftar filesystem, seperti ls atau find, dan editor Anda membuat file sementara dengan # di namanya.
Contoh masalah:
Ups, ini masalahnya:
Ahh, itu lebih baik:
sumber
ls | xargs -I % sh -c 'echo 1 "%"; echo 2 "%"'