Mengapa GNU parallel tidak bekerja dengan "bash -c"?

9
% echo -e '1\n2' | parallel "bash -c 'echo :\$1' '' {}"
:1
:2
% echo -e '1\n2' | parallel bash -c 'echo :\$1' '' {}


%

Saya berharap baris kedua bertindak sama.

Raitis Veinbahs
sumber

Jawaban:

11

parallelmenjalankan perintah di shell sudah (yang shell itu ditentukan oleh parallelmenggunakan heuristik (niat yang untuk memanggil shell sama seperti yang paralleltelah dipanggil dari ). Anda dapat mengatur $PARALLEL_SHELLvariabel untuk memperbaiki shell).

Ini bukan perintah yang Anda berikan parallelseperti yang Anda inginkan untuk perintah envatau xargs, tetapi baris perintah shell (seperti yang Anda lakukan untuk evalperintah).

Seperti untuk eval, di parallel arg1 arg2, paralleladalah menyatukan argumen-argumen itu dengan spasi di antara (sehingga menjadi arg1 arg2) dan string yang diteruskan ke <the-shell> -c.

Untuk argumen yang diteruskan pada parallelstdin, parallelkutip mereka dalam format yang diharapkan oleh shell tertentu (tugas yang sulit dan rawan kesalahan itulah sebabnya Anda akan menemukan ada banyak bug yang diperbaiki di sekitar itu di parallelChangelog ( beberapa masih belum diperbaiki pada 2017-03-06)) dan menambahkannya ke baris perintah itu.

Jadi misalnya, jika dipanggil dari dalam bash,

echo "foo'bar" | parallel echo foo

Akan memiliki panggilan paralel bash -cdengan echo foo foo\'barsebagai baris perintah. Dan jika dipanggil dari dalam rc(atau dengan PARALLEL_SHELL=rc) rc -cdengan echo foo foo''''bar.

Di Anda:

parallel bash -c 'echo :\$1' '' {}

parallel menggabungkan argumen-argumen yang memberikan:

bash -c echo :$1  {}

Dan dengan {}diperluas dan dikutip dalam format yang tepat untuk shell Anda menelepon paralleldari, melewati itu untuk <that-shell> -cyang akan memanggil bash -c echodengan :$1di $0dan perdebatan dalam $1.

Ini bukan cara parallelkerjanya. Di sini, Anda mungkin ingin:

printf '1\n2\n' | PARALLEL_SHELL=bash parallel 'echo :{}'

Untuk melihat apa yang parallelterjadi, Anda dapat menjalankannya di bawah strace -fe execve(atau yang setara di sistem Anda jika bukan Linux).

Di sini, Anda bisa menggunakan GNU xargsalih-alih parallelmendapatkan pemrosesan yang lebih sederhana lebih dekat dengan apa yang Anda harapkan:

printf '1\n2\n' | xargs -rn1 -P4 bash -c 'echo ":$1"' ''

Lihat juga diskusi di https://lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html

Perhatikan bahwa dalam bash -c 'echo foo' '' foo, Anda membuat $0string kosong untuk skrip inline itu. Saya akan menghindari itu karena itu $0juga digunakan dalam pesan kesalahan. Membandingkan:

$ bash -c 'echo x > "$1"' '' /
: /: Is a directory

dengan.

$ bash -c 'echo x > "$1"' bash /
bash: /: Is a directory

Perhatikan juga bahwa membiarkan variabel yang tidak dikutip memiliki arti yang sangat khusus bashdan yang echosecara umum tidak dapat digunakan untuk data yang berubah-ubah.

Stéphane Chazelas
sumber
4
Mon dieu! Ini adalah jawaban yang lebih baik daripada yang bisa ditulis oleh penulis Paralel GNU.
Ole Tange