실제 출력이 아닌 SSH를 통해 스크립트 실행

실제 출력이 아닌 SSH를 통해 스크립트 실행

이런 식으로 ssh를 통해 스크립트를 실행하고 있습니다.

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

문제는 가끔 내가 얻는 출력이 정확하지 않고 줄이 섞여 있다는 것입니다.

내 경우에는 스크립트가 별로 새로운 것이 실행되지 않으며 일반적인 출력은 다음과 같습니다.

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

그러나 때때로 출력은 다음과 같습니다.

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

확실히 이것은 의 실제 출력이 아닙니다 notmuch new. 명령은 다음으로 끝나지만 No new mail한 줄씩이 아니라 ssh를 통해 출력을 얻는 것과 같습니다.

왜 이런 일이 발생합니까?

답변1

버퍼링. 소스코드를 검색해 보면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.");
$ 

이러한 메시지 중 일부는 표준 오류(기본적으로 버퍼링되지 않음)를 사용하고 일부는 표준 출력(표준 출력이 터미널에 대한 것인지 파일에 대한 것인지에 따라 기본적으로 라인 또는 블록 버퍼링됨)을 사용합니다. 이 동작은 표준 C 라이브러리에서 비롯됩니다.setvbuf(3)자세한 내용은. 따라서 stderr메시지는 즉시 작성되지만 printf호출은 stdout표시됩니다...글쎄, 상황에 따라 다릅니다.

버퍼링은 일반적으로 각 응용 프로그램에 의해 개별적으로 구성되지만 다음과 같은 유틸리티를 사용하여 조작할 수도 있습니다 (일부 는 에서 사용하는 트릭이 매우 끔찍하다고 stdbuf생각하지만 ...).LD_PRELOADstdbuf

차이점은 로컬에서 쉽게 재현할 수 있습니다. 예를 들어 터미널에 쓰기(라인 기반 버퍼링 stdout):

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

반면에 정확히 동일한 코드가 대신 파일로 리디렉션되는 경우( 에 대한 블록 기반 버퍼링 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바이트를 수집, 버퍼링 및 전송하는 방법과 클라이언트 시스템에 연결된 notmuch내용을 파악해야 할 수도 있으므로 복잡성이 추가됩니다 .ssh

관련 정보