
에 문제가 있는 것 같습니다 openssh
. 쉘 에서 bash
리디렉션하면 영원히 차단 stderr
되므로 stdout
다음을 수행해야 합니다 KeyboardInterrupt
.
$ ssh -fTNF './config' -MS './sockd5/ctrl_socket' -i './keys/id_rsa' -l 'root' -p '22' 'example.com' 2>&1 | cat -A; echo OK
ControlSocket ./sockd5/ctrl_socket already exists, disabling multiplexing^M$
^C
리디렉션 없이 동일한 명령이 정상적으로 작동합니다.
$ ssh -fTNF './config' -MS './sockd/ctrl_socket' -i './keys/id_rsa' -l 'root' -p '22' 'example.com' | cat -A; echo OK
ControlSocket ./sockd/ctrl_socket already exists, disabling multiplexing
OK
왜 이런 일이 발생합니까? 해결 방법이 있나요?
답변1
호스트에 연결하고 인증한 후 "백그라운드로 이동" 하면 ssh -f
원래 stdin, stdout 및 stderr에 대한 열린 핸들을 계속 유지하므로 해당 핸들이 파이프를 통해 다른 프로세스에 연결된 경우(stdout + stderr) ) 에 대한 예에서는 cat -A
해당 프로세스가 더 이상 필요하지 않더라도 해당 프로세스를 활성 상태로 유지하는 효과가 있습니다.
ssh
호출하여 자신을 데몬화합니다.daemon(3)
라이브러리 함수이지만 로 호출하여 noclose = 1
에서 stdin/stderr/stdout을 리디렉션하지 못하게 합니다 /dev/null
.
openssh
이 문제는 최신 버전 (마스터 제어 프로세스의 경우 - stdin 및 stdout) 에서 부분적으로 수정되었습니다.2010, 표준 오류2016년; 세션 프로세스의 경우 - stdout2017년), 그러나 이전 SSH를 실행해야 하거나 stderr에 대한 집착을 중지해야 하는 경우 유일한 "해결책 LD_PRELOAD
" daemon(3)
은 noclose = 0
.
$ cat daemon-force-close.c
#define _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
int daemon(int nochdir, int noclose){
static int (*orig)(int, int);
if(!orig && !(*(void**)&orig = dlsym(RTLD_NEXT, "daemon")))
errx(1, "%s", dlerror());
return orig(nochdir, 0);
}
$ cc -shared -Wall -O2 daemon-force-close.c -ldl -o daemon-force-close.so
$ LD_PRELOAD=./daemon-force-close.so \
ssh -Nf dummy@localhost -MS ./ctlsock 2>&1 | cat -A
dummy@localhost's password:
$
[no Ctrl-C needed]
$ ssh -S ~/w/c/ctlsock dummy@localhost
Last login: Tue May 28 21:04:26 2019 from ::1
...
답변2
왜 이런 일이 발생합니까?
cat
쉘이 에 도달하기 전에 종료되어야 합니다 echo
. 생명이 있기 때문에 "영원히 차단"됩니다 cat
.
해결 방법이 있나요?
cat
Bash에서는 차단되지 않는 실행을 위해 프로세스 대체를 사용합니다 . cat
방해가 되지 않는 경우에는 정말 괜찮은 경우에만( 또는 을 사용하여) 쉽게 수행 할 echo OK
수 &&
있습니다 $?
. 예:
ssh -f … > >(cat -A) 2>&1 && echo OK; echo "The script goes on."
이제 백그라운드로 이동하기 cat
전후에 작동 ssh
하지만 스크립트는 실행하자마자 (또는 백그라운드로 이동하지 않고 실패하는 ssh
즉시 ) 계속됩니다.ssh