ssh가 종료 된 후 다른 시스템에서 ssh 명령이 예기치 않게 계속됨 종료하면 원격 명령도 종료 될 것으로

아래 명령을 실행하고 다른 시스템에서 출력 파일을 모니터링하고 있습니다.

ssh $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

^C내가 로그인 한 터미널을 사용 하거나 사용하여 ssh 명령을 종료하면 원격 명령도 종료 될 것으로 예상됩니다. 그러나 이런 일이 발생하지는 않습니다. /tmp/count1-5에 관계없이 모든 숫자를 가져오고 ps -ejH쉘과 해당 sleep자식이 계속 실행되는 것을 보여줍니다 .

이것이 예상되는 행동이며 어디에서나 문서화되어 있습니까? 비활성화 할 수 있습니까? 주변에서 읽은 결과, nohup을 사용하여 이러한 종류의 동작을 명시 적으로 활성화해야하지만 기본값이 아닙니다.

ssh 및 sshd에 대한 매뉴얼 페이지를 살펴 보았지만 명백한 점은 발견되지 않았으며 Google 은이 동작을 끄는 것이 아니라 켜는 방법을 지시합니다.

두 시스템 모두에서 루트 로그인과 bash 쉘을 사용하여 Red Hat Enterprise Linux 6.2를 실행하고 있습니다.



답변

uther의 답변 은 터미널을 할당 하라는 메시지를 표시하지만 그 이유는 설명하지 않습니다. 그 이유는 ssh에만 국한된 것이 아니라, 신호 생성과 전파의 문제입니다. 본인은 여러분을 초대 전송하는 다양한 신호의 원인은 무엇? 더 많은 배경.

원격 호스트에는 두 가지 관련 프로세스가 있습니다.

  • sshd원격 프로그램의 입력 및 출력을 로컬 터미널로 중계 하는 ssh 데몬 ( ) 의 인스턴스 ;
  • for루프를 실행하는 쉘

쉘은 루프의 끝에 도달하거나 치명적인 오류가 발생하거나 신호로 인해 자연스럽게 죽을 수 있습니다. 문제는 왜 쉘이 신호를 수신할까요?

원격 쉘이 sshd파이프 를 통해 연결된 경우 , 이는 ssh명령 행에서 명령을 지정할 때 발생하는 것으로 종료되고 쉘이 파이프에 쓰려고 시도 하면 SIGPIPE로sshd 종료됩니다. 쉘이 파이프에 쓰지 않는 한 SIGPIPE를받지 않습니다. 여기서 쉘은 표준 출력에 아무것도 쓰지 않으므로 영원히 살 수 있습니다.

-t옵션을 ssh에 전달하여 원격에서 터미널을 에뮬레이트하고이 터미널에서 지정된 명령을 실행하도록 지시 할 수 있습니다. 그런 다음 SSH 클라이언트가 사라지면 sshd연결을 닫고 종료하여 터미널을 손상시킵니다. 터미널 장치가 사라지면 해당 장치에서 실행중인 프로세스는 SIGHUP을 받습니다 . 따라서 SSH 클라이언트 kill를 종료하거나 ( 또는 클라이언트가 실행중인 터미널을 닫음) 원격 쉘은 SIGHUPped입니다.

-t옵션 을 전달하면 SSH는 SIGINT 도 릴레이 합니다. Ctrl+ 를 누르면 C원격 쉘이 SIGINT를 수신합니다.


답변

ssh명령 으로 psuedo-tty를 할당하십시오 .

ssh -t $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

ssh 세션의 연결을 끊으면 프로세스가 종료됩니다.

이것은 의사 -tty이기 때문에 쉘 초기화는 아마도 구성 파일을 소스하지 않을 것이므로 명령을 거의 환경에 남겨 두지 않을 것입니다. .ssh/environmentPATH와 같은 환경 변수를 정의 하는 파일 을 설정해야 할 수도 있습니다 . 에서man 1 ssh

Additionally, ssh reads ~/.ssh/environment, and adds lines of the format
“VARNAME=value” to the environment if the file exists and users are allowed
to change their environment.  For more information, see the
PermitUserEnvironment option in sshd_config(5).

답변

클라이언트가 종료되거나 종료 될 때 원격 명령이 종료되도록 -t옵션 을 사용하는 대신 , stdin을 닫을 때 명명 된 파이프를 사용하여 “EOF를 SIGHUP”로 변환 할 수 있습니다 ( 버그 396-sshd 참조) pty가 할당되지 않은 경우 고아 프로세스 ).sshsshsshd

# sample code in Bash
# press ctrl-d for EOF
ssh localhost '
TUBE=/tmp/myfifo.fifo
rm -f "$TUBE"
mkfifo "$TUBE"
#exec 3<>"$TUBE"

<"$TUBE" sleep 100 &  appPID=$!

# cf. "OpenSSH and non-blocking mode",
# http://lists.mindrot.org/pipermail/openssh-unix-dev/2005-July/023090.html
#cat >"$TUBE"
#socat -u STDIN "PIPE:$TUBE"
dd of="$TUBE" bs=1 2>/dev/null
#while IFS="" read -r -n 1 char; do printf '%s' "$char"; done > "$TUBE"

#kill -HUP -$appPID
kill $appPID

rm -f "$TUBE"
'

답변

이것이 내가 찾은 가장 좋은 방법입니다. 서버 측에서 stdin을 읽으려고 시도한 후 실패하면 프로세스 그룹을 종료하는 무언가를 원하지만 서버 측 프로세스가 완료 될 때까지 차단하고 <( 수면 무한대).

ssh localhost "sleep 99 < <(cat; kill -INT 0)" <&1

실제로 stdout을 어디에서나 리디렉션하는 것처럼 보이지 않지만 차단 입력으로 작동하고 키 입력을 캡처하지 않습니다.

관련 openssh 버그 : https://bugzilla.mindrot.org/show_bug.cgi?id=396#c14


답변

이를 비활성화하려면 (보통 기본 동작) 클라이언트 또는 서버 측에서 ssh-keep-alive 를 활성화해야합니다 .

맨 페이지에서 ssh-keep-alive-options를 보면 기본적으로 비활성화되어 있음을 알 수 있습니다.


답변

내 대답은 teru를 기반으로합니다. ~/helper서버 server.ip에 도우미 스크립트가 필요합니다 .

#!/bin/bash
TUBE=/tmp/sshCoLab_myfifo.$$;
mkfifo "$TUBE"
( <"$TUBE" "$@" ; rm "$TUBE" ; kill -TERM 0 ) &
cat >"$TUBE" ;
rm "$TUBE" ;
kill -TERM 0 ;

예를 들어

ssh server.ip ~/helper echo hello from server

echo hello from serverserver.ip에서 실행 되면 ssh 클라이언트가 종료됩니다.

예를 들어

ssh server.ip ~/helper sleep 1000 &
CHID=$!

kill -9 $CHID서버에서 스크립트를 중지합니다. 나를 kill -INT $CHID위해, 작동하지 않지만 이유를 모르겠습니다.

teru의 대답으로, ssh 명령은 cat결코 끝나지 않기 때문에 원격 명령이 완료되면 영원히 대기 합니다.

ssh -t의 모든 대답은에서 작동하지 않지만 killCtrl-C에서만 작동했습니다 .

편집 : 나는 이것이 새로운 우분투 14.01에서 더 오래된 과학적 리눅스 상자로 작동한다는 것을 알았습니다. 따라서 일반적인 해결책은 없다고 생각합니다. 기묘한.