Posso desativar o buffer para tr

10

trparece armazenar em buffer sua entrada, para que este comando LongRunningCommand|tr \\n ,comece a produzir somente após a acumulação de alguns kilobytes de entrada do LongRunningCommand.

Existe uma maneira de forçar tra parar esse buffer ou qualquer outro comando que possa substituir novas linhas por outro caractere sem buffer?


PS: Eu já tentei as duas primeiras sugestões do Turn off buffering in pipe, sem sucesso.

ndemou
fonte
1
você se inscreveu stdbufno LongRunningCommand ou no tr, ou em ambos, de maneira diferente?
meuh
Para ambos:stdbuf -o0 fping -aAq -r2 -g 10.30.0.1 10.30.0.255 2>/dev/null | stdbuf -i0 tr \\n ,
ndemou 27/10/2015
fping -qdiz "Não mostrar resultados por sonda, mas apenas o resumo final"; talvez seja necessário apenas uma longa escrita no final?
meuh 27/10/2015
Não, o comando fping funciona bem por si só. Muito obrigado pelas sugestões embora
ndemou 27/10/2015
2
Eu acho que o problema de buffer está realmente na saída de tr. Tente|stdbuf -i0 -o0 tr ...
meuh 27/10/2015

Respostas:

12

Os comandos geralmente não armazenam em buffer suas entradas. Eles fariam um valor read()para um pedaço grande, mas, ao ler de um canal, se não houver muitos bytes no canal, a read()chamada do sistema retornará com o máximo de caracteres existentes e o aplicativo geralmente trabalhará com isso, se puder .

Uma exceção notável é a mawkque permanecerá read()até que o buffer de entrada esteja cheio.

Os aplicativos armazenam em buffer sua saída (stdout). O comportamento usual é que, se a saída estiver indo para um tty, o buffer será em linha (isto é, não começará a gravar no stdout até que tenha uma linha completa para a saída ou um bloco cheio por muito tempo). linha longa), enquanto que para todos os outros tipos de arquivo, o buffer é em blocos (ou seja, não começa a escrever até que haja um bloco completo para escrever (algo como 4KiB / 8KiB ... depende do software e do sistema )).

Portanto, no seu caso, LongRunningCommandprovavelmente armazena em buffer sua saída em blocos (já que sua saída é um pipe e não um tty), e trprovavelmente armazena em buffer sua saída por linha, já que provavelmente é o terminal.

Mas, como você remove todos os caracteres de nova linha de sua saída, ele nunca gera uma linha, portanto o buffer será por bloco.

Então, aqui você deseja desativar o buffer para ambos LongRunningCommande tr. Nos sistemas GNU ou FreeBSD:

stdbuf -o0 LongRunningCommand | stdbuf -o0 tr '\n' ,

Observe que se você deseja unir as linhas com uma vírgula, é melhor usar uma abordagem paste -sd , -. Dessa forma, a saída será finalizada por um caractere de nova linha (você provavelmente ainda precisará desativar o buffer).

Stéphane Chazelas
fonte
@mikeserv. Sim, e aquele que usa buffer stdio e não chama setvbuf / setbuffer ... por si só e não é um shell embutido. Mas geralmente nos sistemas GNU e FreeBSD, todas essas condições são satisfeitas.
Stéphane Chazelas
ah eu só aprendi isso alguns dias atrás, quando fiquei desapontado por não poder afetar os fluxos de E / S dos meus compilados estaticamente sed. desculpe se foi chato - mas eu não percebi que era conhecimento geral. Eu acho que ele usa LD_PRELOAD.
mikeserv
Obrigado pela explicação completa do que acontece Stéphane. Muito apreciado
ndemou 28/10/2015
5

Para substituir novas linhas por ",", você pode executar

awk '{ printf "%s,", $0 }'

O GNU awk ( gawk) e o Solaris nawkserão executados com buffer de linha em stdin e sem buffer de stdout quando a saída for para um terminal. Se o seu awk for mawk, o que acontece no Ubuntu, você pode dar a -W interactiveopção de obter o mesmo comportamento de buffer.

Mark Plotnick
fonte