O caminho mais fácil seria passar por algum programa que define saída sem bloqueio. Aqui está um onliner perl simples (que você pode salvar como leakybuffer ) que faz isso:
, então seu a | b
se torna:
a | perl -MFcntl -e \
'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (<STDIN>) { print }' | b
o que é é ler a entrada e gravar na saída (igual a cat(1)
), mas a saída não é bloqueada - o que significa que se a gravação falhar, retornará erro e perderá dados, mas o processo continuará com a próxima linha entrada como convenientemente ignorar o erro. O processo é do tipo line-buffered como você queria, mas veja a advertência abaixo.
você pode testar com, por exemplo:
seq 1 500000 | perl -w -MFcntl -e \
'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (<STDIN>) { print }' | \
while read a; do echo $a; done > output
você receberá o arquivo output
com linhas perdidas (a saída exata depende da velocidade do seu shell, etc.) assim:
12768
12769
12770
12771
12772
12773
127775610
75611
75612
75613
você vê onde o shell perdeu linhas depois de 12773
, mas também uma anomalia - o perl não tinha buffer suficiente para 12774\n
, mas sim para 1277
, por isso escreveu exatamente isso - e então o próximo número 75610
não inicia no início da linha, tornando-a pouco feia.
Isso pode ser melhorado com a detecção de perl quando a gravação não foi bem-sucedida, e depois tentar liberar o restante da linha ignorando novas linhas, mas isso complicaria muito mais o script perl, então é deixado como um exercício para o leitor interessado:)
Atualização (para arquivos binários): Se você não estiver processando linhas terminadas de nova linha (como arquivos de log ou similares), precisará alterar o comando ligeiramente, ou o perl consumirá grandes quantidades de memória (dependendo da frequência com que caracteres de nova linha aparecem em sua entrada):
perl -w -MFcntl -e 'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (read STDIN, $_, 4096) { print }'
funcionará corretamente também para arquivos binários (sem consumir memória extra).
Update2 - melhor saída de arquivo de texto:
Evitando buffers de saída ( syswrite
em vez de print
):
seq 1 500000 | perl -w -MFcntl -e \
'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (<STDIN>) { syswrite STDOUT,$_ }' | \
while read a; do echo $a; done > output
parece corrigir problemas com "linhas mescladas" para mim:
12766
12767
12768
16384
16385
16386
(Nota: pode-se verificar em quais linhas a saída foi cortada com: perl -ne '$c++; next if $c==$_; print "$c $_"; $c=$_' output
oneliner)