Bagaimana cara menghentikan xargs dari menggabungkan output dari beberapa proses dengan buruk?

17

Saya menggunakan xargsdengan opsi --max-args=0(alternatif -P 0).

Namun, output dari proses digabung ke dalam stdoutaliran tanpa memperhatikan pemisahan garis yang tepat. Jadi saya akan sering berakhir dengan garis-garis seperti:

<start-of-line-1><line-2><end-of-line-1>

Seperti yang saya gunakan egrepdengan ^dalam pola saya pada seluruh xargsoutput ini mengacaukan hasil saya.

Apakah ada cara untuk memaksa xargsuntuk menulis output proses dalam urutan (urutan apa pun, selama output dari satu proses bersebelahan)?

Atau solusi lain?

Edit: detail lebih lanjut tentang use case:

Saya ingin mengunduh dan mem-parsing halaman web dari host yang berbeda. Karena setiap halaman membutuhkan waktu sekitar satu detik untuk memuat dan ada beberapa lusin halaman saya ingin memparalelkan permintaan.

Perintah saya memiliki bentuk berikut:

echo -n $IPs | xargs --max-args=1 -I {} --delimiter ' ' --max-procs=0 \
wget -q -O- http://{}/somepage.html | egrep --count '^string'

Saya menggunakan bash dan bukan sesuatu seperti Perl karena IP host (variabel $ IP) dan beberapa data lainnya berasal dari file bash yang disertakan.

Christoph Wurm
sumber
Bisakah Anda memberikan contoh yang lebih lengkap untuk pertanyaan Anda? Tidak jelas bagaimana atau mengapa Anda menggunakan saat ini xargs.
Caleb
Solusi untuk ini akan sulit, kita perlu menggunakan deskriptor file yang berbeda untuk stdout dari setiap proses dan menggunakan server kecil untuk mengumpulkan baris. xargssepertinya tidak menyediakan fitur seperti itu.
Stéphane Gimenez
@ Caleb Di sana Anda pergi, harap ini membantu :-)
Christoph Wurm
Jelas bukan solusi yang ringan, tapi mungkin Anda bisa menggunakan makefitur pekerjaan, saya pikir makemenggabungkan jalur output dengan benar.
Stéphane Gimenez
tidak menambahkan --line-bufferedbendera untuk egrepmembantu
iruvar

Jawaban:

6

Ini harus melakukan trik:

echo -n $IPs | xargs --max-args=1 -I {} --delimiter ' ' --max-procs=0 \
  sh -c "wget -q -O- 'http://{}/somepage.html' | egrep --count '^string'" | \
  { NUM=0; while read i; do NUM=$(($NUM + $i)); done; echo $NUM; }

Idenya di sini adalah untuk membuat penghitungan yang terpisah dan menjumlahkan ini pada akhirnya. Mungkin gagal jika jumlah yang terpisah cukup besar untuk dicampur, tetapi seharusnya tidak demikian.

Stéphane Gimenez
sumber
14

GNU Parallel dirancang khusus untuk mengatasi masalah ini:

echo -n $IPs | parallel -d ' ' -j0 wget -q -O- http://{}/somepage.html | egrep --count '^string'

Jika IP Anda ada dalam file itu bahkan lebih cantik:

cat IPs | parallel -j0 wget -q -O- http://{}/somepage.html | egrep --count '^string'

Untuk mempelajari lebih lanjut tonton video intro: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ole Tange
sumber
2
Alat yang bagus! Juga, saya bertaruh bahwa seseorang akan memberi tahu Anda bahwa kucing tidak berguna segera.
Stéphane Gimenez
1
Aku tahu. Tetapi saya merasa lebih mudah untuk membaca, dan saya biasanya bekerja pada 48 mesin inti, sehingga beberapa siklus clock tambahan untuk salah satu core idle belum menjadi masalah.
Ole Tange
sejajar akan sempurna untuk pekerjaan itu jika ada di repositori Debian.
Christoph Wurm
1
@Legate Debian menyertakan parallelperintah dari moreutils , yang cukup di sini:parallel -j99 -i sh -c 'wget -q -O- http://{}/somepage.html | egrep -c "^string"' -- $IPs
Gilles 'SO- stop being evil'
@Legate checkout build.opensuse.org/package/… untuk file .deb dan bugs.debian.org/cgi-bin/bugreport.cgi?bug=518696 untuk mendorong bug.
Ole Tange