Suponha que eu queira executar vários programas em paralelo e combinar suas saídas em um único pipe:
sh -c '
(echo qqq; echo qqq2; echo qqq3)&
(echo www; echo www2; echo www3)&
(echo eee; echo eee2; echo eee3)&
wait; wait; wait'
Essa abordagem de shell funciona bem para esse caso simples, mas espero que falhe se os programas produzirem linhas cada vez mais longas no modo buffer, como este (construído):
qqq
qqwww
q2
qqq3www2
wwweee3
eee2
eee3
Uma das soluções que sugeri usar foi tail -f
:
tail -n +0 -q -f <(echo qqq; echo qqq2; echo qqq3) <(echo www; echo www2; echo www3) <(echo eee; echo eee2; echo eee3)
, mas esta é uma opção abaixo do ideal: gera dados com lentidão, não termina; Eu vejo as saídas não na ordem "sleep", mas na ordem dos argumentos neste caso:
tail -n +0 -q -f <(sleep 1; echo qqq; sleep 1; echo qqq2; echo qqq3) <(echo www; echo www2; sleep 10; echo www3) <(echo eee; sleep 4; echo eee2; echo eee3) | cat
Eu implementei um pequeno programa especial para isso, mas acredito que deve haver alguma maneira padrão de fazê-lo.
Como fazer isso usando ferramentas padrão (e sem tail -f
desvantagens)?
shell
io-redirection
Vi.
fonte
fonte
syslog
...syslog
não é para logs, mas para algo personalizado considerado OK?-s
opção de cauda. por exemplotail -f -s .1 file
, reduzirá o atraso do loop para 0,1 segundos do padrão de 1 segundo.Respostas:
Paralelo GNU.
Das notas de versão de agosto de 2013:
Por exemplo:
parallel --line-buffer <jobs
Onde
jobs
contém:short.sh
:long.sh
:Resultado:
fonte
Uma solução implementando bloqueios:
Deve haver uma maneira mais rápida de criar um bloqueio do que usar o sistema de arquivos.
fonte
Não consigo pensar em nada simples, que irá ajudá-lo, se suas linhas forem tão longas, que um programa será enviado para dormir antes que pudesse, para terminar de escrever uma linha para stdout.
No entanto, se suas linhas forem curtas o suficiente para serem gravadas inteiramente antes da alternância do processo, e seu problema é que a geração de uma linha leva muito tempo, você poderá armazenar em buffer a saída usando a leitura.
Por exemplo:
fonte
Você pode criar um pipe nomeado
mkfifo
, despejar toda a saída no pipe nomeado e ler separadamente o pipe nomeado para os dados coletados:fonte
job1
e ajob2
saída de linhas longas (> 4096 bytes)? Isso parece ter o nome de pipe equivalente ao primeiro exemplo de código em questão.tee
, que soa exatamente como você deseja. Possivelmente, observe assyslog
partes internas de ou outras ferramentas de registro, porque elas definitivamente agregam a saída de vários locais em um arquivo de registro. O bloqueio também pode ser a resposta certa, como o @emmanual sugeriu.