Melewati banyak parameter melalui xargs


17

Saya ingin dapat menggunakan xargsuntuk mengeksekusi beberapa parameter di berbagai bagian perintah.

Misalnya, berikut ini:

echo {1..8} | xargs -n2 | xargs -I v1 -I v2 echo the number v1 comes before v2

Saya berharap itu akan kembali

the number 1 comes before 2
the number 3 comes before 4 

... dll

Apakah ini dapat dicapai? Saya menduga bahwa beberapa penggunaan saya -Isalah.

Jawaban:


29

Saya percaya bahwa Anda tidak dapat menggunakan -Icara itu. Tetapi Anda bisa mendapatkan efek / perilaku yang Anda inginkan dengan mengatakan:

echo {1..8} | xargs -n2 sh -c 'echo "the number $1 comes before $2"' sh

Ini, pada dasarnya, membuat skrip shell satu baris ad hoc , yang xargsdijalankan melalui sh -c. Dua nilai yang xargsmem - parsing keluar dari input diteruskan ke "skrip" ini. Shell kemudian memberikan nilai-nilai itu ke $1dan $2, yang kemudian dapat Anda rujuk dalam "skrip".


4
Terima kasih - itu bagus. Saya telah membaca untuk pria itu dan saya sedang berjuang memahami apa panggilan kedua untuk sh lakukan dan, dengan ekstensi, mengapa penghilangannya menghasilkan 'setengah' hasilnya.
Damien Sawyer

6
@DamienSawyer Tidak ada panggilan kedua untuk sh. Jejak shpada akhirnya adalah apa yang dimasukkan $0. $0biasanya yang memegang nama penerjemah atau skrip.
Kusalananda

Saya baru saja mengganti trailing shdengan echo $shyang berfungsi. Jadi shfungsi terakhir sebagai pengganti
kenn

Ya, itu penyederhanaan berlebihan dari apa yang dikatakan Kusalananda.
Scott

6

Dalam kasus khusus printf, Anda selalu dapat melakukan:

echo {1..8} | xargs printf 'the number %s comes before %s\n'

karena printfmemiliki xargskemampuan seperti intrinsik untuk mengeksekusi beberapa kali jika diberikan lebih banyak argumen daripada yang dibutuhkan untuk doa tunggal. Meskipun itu memiliki sedikit kelebihan

printf 'the number %s comes before %s\n' {1..8}

Dan untuk daftar besar, xargsperintah sederhana dapat menghasilkan xargsmenjalankan beberapa contoh printf, beberapa di antaranya mungkin memiliki jumlah argumen ganjil. Anda dapat beralih -n 1000ke xargsuntuk menjaga itu, di mana 1000 adalah bilangan genap yang harus cukup kecil sehingga tidak mencapai batas daftar arg terlalu lama dan cukup besar untuk menghindari menjalankan begitu banyak printfs.

Catatan yang xargsakan memanggil, bukan builtin shell Anda printf, tetapi eksternal printf, dengan setiap doa dalam proses baru yang terpisah.

Perhatikan juga bahwa untuk input kosong, kecuali pada beberapa BSD, itu akan tetap berjalan printfsekali tanpa argumen. GNU xargsdan yang kompatibel memiliki opsi -r (atau --no-run-if-empty) untuk menghindarinya.

Agar lebih jelas, jawaban sederhana ini khusus untuk printfcontoh Anda , dan tidak akan berfungsi dalam kasus umum di mana Anda harus melewatkan dua parameter sekaligus ke perintah Anda (seperti halnya untuk diff, misalnya). Untuk mengatasi masalah umum zsh, Anda dapat menggunakan:

for i j ({1..8}) echo "the number $i comes before $j"

(1) IMHO, zshbagian di atas adalah jawaban nyata, dan bagian xargs-with-no-options hanyalah sebuah keanehan. Dalam kasus seperti itu, saya akan mempertimbangkan untuk menempatkan jawaban yang sebenarnya terlebih dahulu. (2) Saya menganggap Anda memiliki alasan untuk tidak menggunakan tanda kutip dalam zshperintah Anda . Jika demikian, Anda mungkin ingin menyatakannya, jangan sampai orang membaca di atas dan mulai berpikir bahwa kutipan tidak penting. (Atau cukup sertakan mereka, karena mereka tidak terluka.)
Scott

Ini sangat keren. Saya mendarat di sini mencari sesuatu yang serupa di mana saya tidak yakin sebelumnya berapa banyak args yang akan saya terima yang harus dimasukkan ke dalam baris perintah arg berikutnya. melakukan sesuatu sepertiawk -F'\t' '/match/{printf $1"\0"$2"\0"}' | xargs -0 printf -- '-args1 "%s" -args2 "%s"' | xargs mycommand
keithpjolley

@keithpjolley, penggunaan Anda -0pada yang pertama xargsuntuk membuatnya lebih dapat diandalkan dikalahkan oleh Anda tidak menggunakannya pada yang kedua. Juga, argumen pertama untuk printf(baik utilitas mandiri dan awk's printf()fungsi) adalah format, Anda tidak harus menggunakan variabel di sana. Di sini, Anda bisa melakukannya awk -F'\t' '/match/{printf "-args1\0%s\0-args2\0%s\0", $1, $2}' | xargs -n400 -r0 mycommand. Sekali lagi, -n400diperlukan untuk memastikan xargsmelewati sejumlah argumen yang merupakan kelipatan dari 4. (perhatikan bahwa tidak semua awkimplementasi mendukung menggunakan \0seperti itu di sini).
Stéphane Chazelas

tidak digunakan -0untuk membuatnya lebih dapat diandalkan, menggunakannya untuk melakukan apa yang ingin saya lakukan, yang dilakukannya.
keithpjolley

2

coba ini:

echo {1..8} |xargs -n 2 bash -c 'echo "the number $0 comes before $1"'

2
Ini akan berfungsi dalam kasus ini, tetapi lebih baik menjalankan sh -cskrip dengan sh(atau apa pun) di $0. Catatan yang $0tidak termasuk dalam $@apakah ini akan digunakan oleh sh -cskrip, misalnya jika skrip ituecho "the two numbers were $@"
Kusalananda
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.