startup.sh
핵심 라인이 다음과 같은 python3 스크립트(라고 부르자)를 시작하는 bash 스크립트가 있습니다 .
nohup python3 -u <script> &
직접 들어가서 이 스크립트를 호출 하면 ssh
Python 스크립트는 종료 후에도 백그라운드에서 계속 실행됩니다. 그러나 이것을 실행하면 다음과 같습니다.
ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "./startup.sh"
프로세스는 실행이 완료되고 ssh
세션이 닫히자마자 종료됩니다.
둘 사이의 차이점은 무엇입니까?
편집: Python 스크립트는 Bottle을 통해 웹 서비스를 실행하고 있습니다.
EDIT2: 나도 시도해봤어초기화 스크립트 생성을 호출 startup.sh
하고 실행했지만 ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "sudo service start <servicename>"
동일한 동작을 보였습니다.
EDIT3: 어쩌면 스크립트의 다른 것일 수도 있습니다. 다음은 스크립트의 대부분입니다.
chmod 700 ${key_loc}
echo "INFO: Syncing files."
rsync -azP -e "ssh -i ${key_loc} -o StrictHostKeyChecking=no" ${source_client_loc} ${remote_user}@${remote_hostname}:${destination_client_loc}
echo "INFO: Running startup script."
ssh -i ${key_loc} -o StrictHostKeyChecking=no ${remote_user}@${remote_hostname} "cd ${destination_client_loc}; chmod u+x ${ctl_script}; ./${ctl_script} restart"
EDIT4: 마지막 줄을 실행하고 마지막에 잠을 자면 다음과 같습니다.
ssh -i ${key_loc} -o StrictHostKeyChecking=no ${remote_user}@${remote_hostname} "cd ${destination_client_loc}; chmod u+x ${ctl_script}; ./${ctl_script} restart; sleep 1"
echo "Finished"
결코 도착하지 않았고 echo "Finished"
이전에 본 적이 없는 Bottle 서버 메시지가 표시됩니다.
Bottle vx.x.x server starting up (using WSGIRefServer())...
Listening on <URL>
Hit Ctrl-C to quit.
SSH를 통해 수동으로 로그인하고 프로세스를 직접 종료하면 "완료됨"이 표시됩니다.
EDIT5: EDIT4를 사용하여 엔드포인트에 요청하면 페이지가 반환되지만 Bottle에 오류가 발생합니다.
Bottle vx.x.x server starting up (using WSGIRefServer())...
Listening on <URL>
Hit Ctrl-C to quit.
----------------------------------------
Exception happened during processing of request from ('<IP>', 55104)
답변1
표준 입력/출력 및 오류 스트림에서 명령의 연결을 끊겠습니다.
nohup python3 -u <script> </dev/null >/dev/null 2>&1 &
ssh
더 이상 출력이 없고 추가 입력이 필요하지 않은 표시기가 필요합니다. 다른 것을 입력으로 사용하고 출력을 리디렉션한다는 것은 ssh
입력/출력이 터미널에서 나오거나 터미널로 가지 않기 때문에 종료하는 것이 안전하다는 것을 의미합니다. 이는 입력이 다른 곳에서 와야 하고 출력(STDOUT 및 STDERR)이 다른 곳에서 와야 함을 의미합니다.
이 부분은 입력으로 </dev/null
지정됩니다 . 이것이 유용한 이유:/dev/null
<script>
/dev/null을 stdin으로 리디렉션하면 해당 프로세스의 모든 읽기 호출에 대해 즉각적인 EOF가 제공됩니다. 이는 tty에서 프로세스를 분리하는 데 종종 유용합니다(이러한 프로세스를 데몬이라고 함). 예를 들어 SSH를 통해 원격으로 백그라운드 프로세스를 시작할 때 프로세스가 로컬 입력을 기다리지 않도록 stdin을 리디렉션해야 합니다. https://stackoverflow.com/questions/19955260/what-is-dev-null-in-bash/19955475#19955475
또는 ssh
현재 세션이 열려 있을 필요가 없는 한 다른 입력 소스에서 리디렉션하는 것이 상대적으로 안전해야 합니다.
이 >/dev/null
섹션을 사용하여 쉘은 표준 출력을 /dev/null로 리디렉션하여 기본적으로 이를 폐기합니다. >/path/to/file
작동할 것입니다.
마지막 부분은 2>&1
STDERR을 STDOUT으로 리디렉션하는 것입니다.
프로그램에는 세 가지 표준 입력 및 출력 소스가 있습니다. 대화형 프로그램인 경우 표준 입력은 일반적으로 키보드에서 제공됩니다. 다른 프로그램의 출력을 처리하는 경우 표준 입력은 일반적으로 다른 프로그램에서 제공됩니다. 프로그램은 일반적으로 표준 출력으로 인쇄하고 때로는 표준 오류로 인쇄합니다. 이 세 가지 파일 설명자("데이터 파이프"로 생각할 수 있음)는 일반적으로 STDIN, STDOUT 및 STDERR이라고 합니다.
때로는 이름이 지정되지 않았지만 번호가 매겨져 있습니다! 내장된 숫자는 순서대로 0, 1, 2입니다. 기본적으로 명시적으로 이름이나 번호를 먼저 지정하지 않으면 STDOUT에 대해 이야기하는 것입니다.
이 경우 위 명령이 표준 출력을 /dev/null로 리디렉션하여 필요하지 않은 항목(종종 비트버킷이라고 함)을 덤프할 수 있는 곳에서 표준 오류를 표준 출력으로 리디렉션하는 것을 볼 수 있습니다. 목적지 앞의 &).
따라서 간단히 설명하면 "이 명령의 모든 출력은 블랙홀로 푸시되어야 합니다"입니다. 이것은 프로그램을 정말 조용하게 만드는 좋은 방법입니다!
> /dev/null 2>&1 무슨 뜻인가요? Xaprb |
답변2
보고 man ssh
:
ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname [command]
실행하면 ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "./startup.sh"
쉘 스크립트 start.sh가 ssh 명령으로 실행됩니다.
설명에서:
명령이 지정되면 로그인 쉘이 아닌 원격 호스트에서 실행됩니다.
이를 기반으로 스크립트를 원격으로 실행해야 합니다.
로컬 터미널에서 실행하는 것과 다른 점은 nohup python3 -u <script> &
로컬 백그라운드 프로세스로 실행되는 반면 ssh 명령은 원격 백그라운드 프로세스로 실행하려고 시도한다는 것입니다.
이 스크립트를 로컬로 실행하려는 경우 ssh 명령의 일부로 시작.sh를 실행하지 마십시오. 다음과 같은 것을 시도해 볼 수 있습니다.ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> && "./startup.sh"
스크립트를 원격으로 실행하고 SSH 세션이 종료된 후 프로세스를 계속하려면 먼저 screen
원격 호스트에서 세션을 시작해야 합니다. 그런 다음 화면에서 Python 스크립트를 실행해야 하며 SSH 세션을 종료한 후에도 계속 실행됩니다.
바라보다화면 매뉴얼
저는 screen이 최선의 선택이라고 생각하지만, nohup을 사용해야 한다면 shopt -s huponexit
nohup 명령을 실행하기 전에 원격 호스트에 설정하는 것을 고려해 보세요. 또는 disown -h [jobID]
프로세스에 SIGHUP이 전송되지 않도록 표시할 수 있습니다.1
백그라운드 셸 프롬프트를 종료한 후 작업을 계속 실행하려면 어떻게 해야 합니까?
SIGHUP(hangup) 신호는 제어 터미널이나 제어 프로세스가 종료될 때 시스템에서 사용됩니다. SIGHUP을 사용하여 구성 파일을 다시 로드하고 로그 파일을 열거나 닫을 수도 있습니다. 즉, 터미널에서 로그아웃하면 실행 중인 모든 작업이 종료됩니다. 이러한 상황을 방지하려면 -h 옵션을 disown 명령에 전달할 수 있습니다. 이 옵션은 쉘이 SIGHUP을 수신할 때 SIGHUP이 작업으로 전송되지 않도록 각 작업 ID를 표시합니다.
huponexit
또한 쉘이 종료, 종료 또는 삭제될 때 쉘이 작동하는 방식에 대한 요약을 참조하십시오. 현재 문제는 쉘 세션이 끝나는 방식과 관련이 있는 것 같습니다.2
huponexit 옵션이 설정된 경우에만 SSH 연결을 통해 열린 쉘의 모든 하위 프로세스(백그라운드 여부에 관계없이)는 SSH 연결이 닫힐 때 SIGHUP으로 종료됩니다. 이것이 사실인지 확인하려면 shopt huponexit를 실행하세요.
huponexit가 true인 경우 nohup 또는 disown을 사용하여 프로세스가 종료 시 종료되지 않도록 셸에서 프로세스를 분리할 수 있습니다. 또는 화면을 사용하여 작업을 실행하세요.
huponexit가 false(현재 일부 Linux에서는 기본값)이면 일반 로그아웃 시 백그라운드 작업이 종료되지 않습니다.
- 하지만 huponexit가 false인 경우에도 ssh 연결이 종료되거나 연결이 끊어지면(일반 로그아웃과 달리) 백그라운드 프로세스는 계속 종료됩니다. 이는 (2)에서 disown 또는 nohup을 사용하여 피할 수 있습니다.
마지막으로 shopt huponexit 사용 방법에 대한 몇 가지 예는 다음과 같습니다.삼
$ shopt -s huponexit; shopt | grep huponexit
huponexit on
# Background jobs will be terminated with SIGHUP when shell exits
$ shopt -u huponexit; shopt | grep huponexit
huponexit off
# Background jobs will NOT be terminated with SIGHUP when shell exits
답변3
-n
어쩌면 처음에 옵션을 시도해 볼 가치가 있을까요 ssh
? 이는 원격 프로세스가 로컬 프로세스에 의존하는 것을 방지하며 stdin
, 로컬 프로세스는 ssh session
종료되면 닫힙니다. .stdin
답변4
python
이는 스크립트나 python
스크립트 자체 의 문제인 것처럼 들립니다 . 실제로 수행된 모든 작업(리디렉션을 단순화하는 것 외에)은 프로그램을 실행하기 전에 nohup
신호 핸들러를 HUP
(무시)로 설정하는 것입니다. 프로그램이 실행되기 시작하면 프로그램이 다시 설정 되거나 자체 처리기를 설치하는 것을 SIG_IGN
막을 수 없습니다 .SIG_DFL
시도해 볼 수 있는 한 가지는 명령을 괄호로 묶어 이중 분기 효과를 얻고 스크립트가 python
더 이상 셸 프로세스의 하위 프로세스가 되지 않도록 하는 것입니다. 예를 들어:
( nohup python3 -u <script> & )
시도해 볼 만한 또 다른 방법은(다른 셸 대신 사용하는 경우 ) 내장된 셸을 대신 bash
사용하는 것입니다 . 모든 것이 문서화된 대로 작동한다면 실제로 아무런 차이가 없지만 대화형 셸에서는 이렇게 하면 문제가 발생하는 것을 방지할 수 있습니다. 신호가 스크립트 에 전파되지 않도록 합니다 . 다음 줄이나 아래와 같은 줄에 disown을 추가할 수 있습니다( a 뒤에 a를 추가하는 것은 오류입니다 ).disown
nohup
HUP
python
;
&
bash
python3 -u <script> </dev/null &>/dev/null & disown
위 방법이나 일부 조합이 작동하지 않으면 문제를 해결할 수 있는 유일한 곳은 python
스크립트 자체입니다.