Estou executando um script via ssh desta forma:
ssh user@host 'bash -s' < ./script.sh
o problema é que, às vezes, a saída que recebo não está correta, as linhas ficam misturadas.
No meu caso, o script não é executado de forma muito nova, a saída normal é algo como:
...
Note: Ignoring non-mail file: foobar
Note: Ignoring non-mail file: foobar
Note: Ignoring non-mail file: foobar
Processed 93 total files in almost no time.
No new mail.
mas às vezes a saída é algo como:
...
Note: Ignoring non-mail file: foobar
Note: Ignoring non-mail file: foobar
Processed 93 total files in almost no time.
No new mail.
Note: Ignoring non-mail file: foobar
Note: Ignoring non-mail file: foobar
e com certeza esta não é a saída real de notmuch new
, o comando termina com No new mail
mas é como se obtivesse a saída via ssh, não linha por linha.
Por que isso aconteceu?
Responder1
Carregando. Se pesquisarmos o código-fonte pornotmuch
$ find . -name \*.c -exec grep 'Ignoring non-mail file' {} +
./notmuch-new.c: fprintf (stderr, "Note: Ignoring non-mail file: %s\n", filename);
$ find . -name \*.c -exec grep 'No new mail' {} +
./notmuch-new.c: printf ("No new mail.");
$
Algumas dessas mensagens usam erro padrão (que não tem buffer por padrão) e algumas usam saída padrão (que tem buffer de linha ou bloco por padrão, dependendo se a saída padrão é para um terminal ou para um arquivo). Este comportamento vem da biblioteca C padrão, consultesetvbuf(3)
para detalhes. Assim, stderr
as mensagens são escritas imediatamente, enquanto as printf
chamadas stdout
aparecerão... bem, depende.
O buffer normalmente é configurado por cada aplicativo individualmente, embora talvez possa ser manipulado com o uso de utilitários como stdbuf
(embora alguns considerem os LD_PRELOAD
truques usados por stdbuf
bastante horríveis ...).
A diferença é fácil de reproduzir localmente; por exemplo, escrevendo no terminal (buffering baseado em linha para stdout
):
$ perl -E 'for (1..4) { say "out"; warn "err\n" }'
out
err
out
err
out
err
out
err
$
enquanto, em vez disso, se exatamente o mesmo código for redirecionado para um arquivo (buffering baseado em bloco para stdout
):
$ perl -E 'for (1..4) { say "out"; warn "err\n" }' >x 2>&1
$ cat x
err
err
err
err
out
out
out
out
$
ssh
adiciona uma camada adicional de complicação, pois também pode ser necessário descobrir como ele está coletando, armazenando em buffer e enviando bytes, além do notmuch
que ssh
está conectado no sistema do cliente...