Como impedir que xargs mescla mal a saída de vários processos?

17

Estou usando xargscom a opção --max-args=0(como alternativa -P 0).

No entanto, a saída dos processos é mesclada no stdoutfluxo sem levar em consideração a separação de linha adequada. Então, muitas vezes acabo com linhas como:

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

Como eu estou usando egrepcom ^no meu padrão em toda a xargssaída isto é estragar o meu resultado.

Existe alguma maneira de forçar xargsa gravação das saídas do processo em ordem (qualquer ordem, desde que a saída de um processo seja contígua)?

Ou alguma outra solução?

Edit: mais detalhes sobre o caso de uso:

Quero baixar e analisar páginas da web de diferentes hosts. Como cada página leva cerca de um segundo para carregar e há algumas dúzias de páginas, eu quero paralelizar as solicitações.

Meu comando tem o seguinte formato:

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

Eu uso o bash e não algo como Perl porque os IPs do host (a variável $ IPs) e alguns outros dados vêm de um arquivo bash incluído.

Christoph Wurm
fonte
Você pode dar um exemplo mais completo para sua pergunta? Não está claro como ou por que você está usando no momento xargs.
Caleb
A solução para isso será difícil, é preciso usar descritores de arquivos diferentes para os stdout de cada processo e usar um pequeno servidor para coletar as linhas. xargsparece não fornecer esse recurso.
Stéphane Gimenez
@Caleb Lá vai você, espero que isso ajude :-)
Christoph Wurm
Definitivamente não é uma solução leve, mas talvez você possa usar makeo recurso de trabalhos, acho que makemescla as linhas de saída corretamente.
Stéphane Gimenez
faz adicionando a --line-bufferedbandeira para egrepajuda
Iruvar

Respostas:

6

Isso deve fazer o truque:

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; }

A idéia aqui é fazer contagens separadas e somar no final. Pode falhar se as contagens separadas forem grandes o suficiente para serem misturadas, mas não deve ser o caso.

Stéphane Gimenez
fonte
14

O GNU Parallel foi projetado especificamente para resolver este problema:

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

Se seus IPs estão em um arquivo, é ainda mais bonito:

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

Para saber mais, assista ao vídeo de introdução: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ole Tange
fonte
2
Nice tool! Além disso, estou apostando que alguém lhe dirá que o gato é inútil muito em breve.
Stéphane Gimenez
1
Eu sei. Mas acho mais fácil ler e geralmente trabalho em máquinas com 48 núcleos; portanto, os poucos ciclos de clock extras para um dos núcleos ociosos ainda precisam ser um problema.
precisa
paralelo seria perfeito para o trabalho se estivesse nos repositórios Debian.
Christoph Wurm
1
O @Legate Debian inclui o parallelcomando do moreutils , o que é suficiente aqui:parallel -j99 -i sh -c 'wget -q -O- http://{}/somepage.html | egrep -c "^string"' -- $IPs
Gilles 'SO- stop be evil'
@Legate checkout build.opensuse.org/package/… para um arquivo .deb e bugs.debian.org/cgi-bin/bugreport.cgi?bug=518696 para que o bug seja enviado .
precisa