Ausführen eines Skripts über SSH, keine echte Ausgabe

Ausführen eines Skripts über SSH, keine echte Ausgabe

Ich führe ein Skript über SSH folgendermaßen aus:

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

das Problem besteht darin, dass die Ausgabe, die ich erhalte, manchmal nicht korrekt ist und die Zeilen gemischt sind.

In meinem Fall führt das Skript nicht viel Neues aus, die normale Ausgabe ist etwa:

...
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.

aber manchmal ist die Ausgabe etwa:

...
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

und das ist mit Sicherheit nicht die tatsächliche Ausgabe von notmuch new, der Befehl endet mit, No new mailaber es ist, als würde er die Ausgabe über SSH erhalten und nicht zeilenweise.

Warum passiert das?

Antwort1

Pufferung. Wenn wir den Quellcode durchsuchen nachnotmuch

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

Einige dieser Nachrichten verwenden die Standardfehlerausgabe (die standardmäßig ungepuffert ist) und einige die Standardausgabe (die standardmäßig zeilen- oder blockgepuffert ist, je nachdem, ob die Standardausgabe an ein Terminal oder an eine Datei erfolgt). Dieses Verhalten stammt aus der Standard-C-Bibliothek, siehesetvbuf(3)für Details. stderrNachrichten werden also sofort geschrieben, während die printfAufrufe stdoutangezeigt werden... nun, es kommt darauf an.

Das Puffern wird normalerweise von jeder Anwendung einzeln konfiguriert, man kann aber vielleicht mit Dienstprogrammen wie herumspielen stdbuf(obwohl manche die LD_PRELOADvon verwendeten Tricks stdbuffür ziemlich schrecklich halten ...).

Der Unterschied lässt sich lokal leicht reproduzieren, beispielsweise beim Schreiben ins Terminal (zeilenbasierte Pufferung für stdout):

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

während stattdessen derselbe Code in eine Datei umgeleitet wird (blockbasierte Pufferung für stdout):

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

sshfügt eine zusätzliche Komplikationsebene hinzu, da man möglicherweise auch herausfinden muss, wie es Bytes sammelt, puffert und sendet, und außerdem, notmuchwas sshauf dem Clientsystem verkabelt ist …

verwandte Informationen