ejecutar un script a través de ssh, no una salida real

ejecutar un script a través de ssh, no una salida real

Estoy ejecutando un script vía ssh de esta manera:

 ssh user@host 'bash -s' < ./script.sh

el problema es que, a veces, el resultado que obtengo no es correcto, las líneas están mezcladas.

En mi caso, el script no se ejecuta muy nuevo, el resultado normal es 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.

pero a veces el resultado es 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

y seguro que este no es el resultado real de notmuch new, el comando termina con No new mailpero es como si obtuviera el resultado a través de ssh, no línea por línea.

¿Por qué sucede esto?

Respuesta1

Almacenamiento en búfer. Si buscamos en el código fuentenotmuch

$ 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.");
$ 

Algunos de esos mensajes usan error estándar (que no tiene buffer de forma predeterminada) y otros usan salida estándar (que tiene buffer de línea o de bloque de manera predeterminada, dependiendo de si la salida estándar es a una terminal o a un archivo). Este comportamiento proviene de la biblioteca C estándar, consultesetvbuf(3)para detalles. Así, stderrlos mensajes se escriben inmediatamente, mientras que las printfllamadas a stdoutaparecerán... bueno, depende.

El almacenamiento en búfer generalmente lo configura cada aplicación individualmente, aunque tal vez se pueda jugar con utilidades como stdbuf(aunque algunos consideran que los LD_PRELOADtrucos utilizados stdbufson bastante horribles...).

La diferencia es fácil de reproducir localmente; por ejemplo, escribiendo en la terminal (almacenamiento en búfer basado en líneas para stdout):

$ perl -E 'for (1..4) { say "out"; warn "err\n" }'
out
err
out
err
out
err
out
err
$ 

mientras que, en cambio, si exactamente ese mismo código se redirige a un archivo (almacenamiento en búfer basado en bloques 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
$ 

sshagrega una capa adicional de complicación, ya que es posible que también haya que descubrir cómo se recopilan, almacenan en el búfer y envían bytes, además de a notmuchqué sshestá conectado en el sistema cliente...

información relacionada