ssh가 종료 된 후 다른 시스템에서 ssh 명령이 예기치 않게 계속됨


11

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

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를 실행하고 있습니다.

답변:


11

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 자체에 tty가 할당되지 않은 경우 -tt대신 사용하십시오 -t. ssh가 -f또는 같은 옵션을 통해 호출하자마자 백그라운드 화되면 SSH는 할당 된 tty를받지 않습니다 -n.
— Miron V

3

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

2

클라이언트가 종료되거나 종료 될 때 원격 명령이 종료되도록 -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"
'

1

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

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

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

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


0

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

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


0

내 대답은 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에서 더 오래된 과학적 리눅스 상자로 작동한다는 것을 알았습니다. 따라서 일반적인 해결책은 없다고 생각합니다. 기묘한.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.