wykonanie skryptu przez ssh, a nie rzeczywiste wyjście

2

W ten sposób wykonuję skrypt przez ssh:

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

problem polega na tym, że czasami dane wyjściowe, które otrzymuję, nie są poprawne, linie są mieszane.

W moim przypadku skrypt wykonuje niewiele nowych, normalne wyjście to coś w stylu:

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

ale czasami wynik jest podobny do:

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

i na pewno nie jest to rzeczywiste wyjście z notmuch new, polecenie kończy się na No new mail ale to tak, jakby pobierało wyjście przez ssh, a nie po linii.

Dlaczego tak się stało?

res1
źródło
1
Zgaduję: część wyjścia to stdout, inne wyjście to stderr. Jeśli przejście nie interaktywne, buforowanie może się różnić, zmieniając kolejność.
A.B

Odpowiedzi:

5

Buforowanie. Jeśli przeszukamy kod źródłowy notmuch

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

Niektóre z tych komunikatów używają standardowego błędu (domyślnie niebuforowanego), a niektóre używają standardowego wyjścia (domyślnie buforowanego liniowo lub blokowo, w zależności od tego, czy standardowe wyjście jest na terminal, czy na plik). To zachowanie pochodzi ze standardowej biblioteki C, patrz setvbuf(3) dla szczegółów. A zatem stderr wiadomości są pisane natychmiast, podczas gdy printf połączenia do stdout pokaże się ... cóż, to zależy.

Buforowanie jest zazwyczaj konfigurowane indywidualnie przez każdą aplikację, choć może być małpią przy użyciu narzędzi, takich jak stdbuf (choć niektórzy uważają LD_PRELOAD sztuczki używane przez stdbuf być okropnym ...).

Różnica jest łatwa do odtworzenia lokalnie; na przykład zapis na terminalu (buforowanie liniowe dla stdout ):

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

natomiast zamiast tego ten sam kod jest zamiast tego przekierowywany do pliku (buforowanie blokowe dla 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 dodaje dodatkową warstwę komplikacji, jako że można również dowiedzieć się, jak gromadzi, buforuje i wysyła bajty, oprócz notmuch I co wtedy ssh jest podłączony do systemu klienta ...

thrig
źródło
Rozumiem twój punkt widzenia, ale dlaczego to zachowanie jest pokazywane tylko zdalnie?
res1
łatwo jest pokazać problem lokalnie, oprócz komplikacji ssh dodaje.
thrig
P.S. rzeczy mogą pójść jeszcze gorzej, jeśli spróbujesz współbieżnego odczytu / zapisu do tego samego gniazda - unix.stackexchange.com/questions/364396/… - jak w przypadku możliwego uszkodzenia danych
thrig