Unix에서 nohup 명령의 종료 코드 문제

Unix에서 nohup 명령의 종료 코드 문제

나는 nohup 명령의 종료 상태를 캡처한 다음 해당 상태에 따라 메일을 보내는 방법을 알아내려고 노력해 왔습니다.

아래는 내 코드입니다.

if [[ "" !=  "$PID" ]]; then
    echo "killing $PID"
    kill -9 $PID
    nohup java -jar Xyz-port-0.0.1.jar &
    << Exit Code and then send mail if Exit 
      code is 0>>
    else 
    echo "Process doesn't exist"
    fi

답변1

백그라운드 작업은언제나성공적으로 시작되었습니다:

$ sntaoehu &
[1] 33566
$ bash: sntaoehu: command not found
[1]+  Exit 127                sntaoehu
$ echo $?
0

nohup백그라운드에서 Java 프로그램을 시작할 수 없으며 명령이 종료될 때까지 원활하게 실행되는지 여부를 감지할 수 없습니다. 명령 nohup을 찾거나 시작할 수 없거나 javaJava 프로그램이 종료될 때마다 명령이 종료됩니다. nohup백그라운드에서 프로그램을 실행 하지 않습니다 . 이는 단순히 프로그램이 모든 신호를 무시하도록 HUP하고 프로그램이 종료될 때까지 정지한 다음 프로그램의 종료 상태를 호출 쉘에 반환합니다.

작업이 시작되면 이메일 보내기실패, 넌 할 수있어

(
    nohup java -jar Xyz-port-0.0.1.jar
    status=$?
    if [ "$status" -eq 126 ] || [ "$status" -eq 127 ]; then
        # something wrong in launching java
        echo 'nohup failed to run java'
        printf 'nohup exit status is %s\n' "$status"
    elif [ "$status" -ne 0 ]; then
        # the java code returned an error
        echo 'java returned an error'
        printf 'java exit status is %s\n' "$status"
    else
        # everything went well and java exited ok
        echo 'java exited safely'
    fi | mail -s 'java job status report' [email protected]
) &

echo 'started background job'

즉, 백그라운드 하위 셸을 시작하고 그 안에서 프로그램을 실행한 다음 126 또는 127이 반환되는지 테스트합니다. 명령을 찾을 수 없거나 시작할 수 없는 경우 nohup이 작업을 수행합니다 .java

답변2

이와 같은 방법은 프로세스의 종료 코드를 보다 안정적으로 캡처합니다.

parent.sh

...
java -jar Xyz-port-0.0.1.jar > /dev/null & #optionally discard stdout of java
child=$!
wait $child
exit_status=$?
if [[ "$exit_status" -ne 0 ]]; then
    # handle error
else
    #handle success
fi

기다리다

호출은 wait무기한 차단되므로 명령이 완료되는 데 걸리는 시간을 임의로 제한해야 하는 경우 java호출을 루프로 바꾸고 수동으로 검사하여 프로세스가 아직 실행 중인지 확인할 수 있습니다. 달리기. 이렇게 하면 감시 장치를 설정하고 프로세스가 중단된 경우 풀에서 모든 사람에게 전화를 걸 수 있습니다.waitps

북면

nohup활성 터미널 세션에 있지 않고 Java 프로세스를 실행하고 해당 종료 코드를 처리해야 하는 경우 코드 대신 상위 스크립트(위)를 호출하세요 java. 상위 스크립트는 nohup편집될 수 있으며 제어 터미널 없이 백그라운드에서 유지되며 이메일 전송 또는 정리를 안정적으로 수행합니다.

답변3

문제는 반드시 nohup명령 이 아니라 &명령줄 끝에 있는 문제입니다.

매뉴얼 페이지에는 다음과 bash같이 나와 있습니다.

명령이 제어 연산자 &에 의해 종료되면 쉘은 서브쉘의 백그라운드에서 명령을 실행합니다. 쉘은 명령이 완료될 때까지 기다리지 않고 상태 0을 반환합니다.

기술적으로 쉘은 nohup ...명령을 실행하기 위해 하위 쉘을 분기하고 스크립트를 실행하는 기본 쉘은 즉시 스크립트의 다음 명령을 계속 실행합니다. 따라서 메인 쉘이 이 nohup ... &라인 이후의 행을 실행할 때 nohup 명령이 종료되지 않았을 수 있습니다. 서브 쉘이 실행을 위해 이를 로드 중일 수 있습니다.

그리고 nohup명령이 반드시 다음과 같이 종료되는 것은 아닙니다. HUP 신호를 무시하도록 신호 처리기를 설정한 다음 명령을 직접 실행하려고 시도 exec()합니다 java .... exec()시스템 호출이 성공 하면 프로세스는 nohup다음으로 전환됩니다.java fork()새로운 프로세스를 생성하고 종료할 필요가 없습니다 .이므로 아직 반환할 종료 코드가 없습니다.

nohup실제 명령이 종료 코드를 반환하는 유일한 방법은 java명령을 찾거나 실행할 수 없거나 nohup명령 자체에 내부 오류가 있는 경우입니다. exec()시스템 호출이 성공 하면 종료 코드를 사용할 수 있는 유일한 시간은 java명령 자체가 끝날 때입니다.

이것이 바로 이와 같은 시도가 원하는 효과를 얻지 못하는 이유이기도 합니다.

nohup java -jar Xyz-port-0.0.1.jar &
wait $! 
if [ $? -ne 0 ]; then
    echo "Error in running Java"
fi

nohup백그라운드에서 실패 하면 wait종료 코드를 가져와 확인할 수 있지만 nohup성공적으로 시작 하면 java명령은 종료될 wait때까지 기다립니다 . 왜냐하면 두 및 모두 동일한 프로세스에서 차례로 실행되기 때문입니다.javanohupjava

@datUser가 제안한 대로 다음과 같은 작업을 수행할 수 있습니다.

STARTWAIT=20 #number of seconds to wait after starting the service

nohup java -jar Xyz-port-0.0.1.jar &
NEWPID=$!
for i in $(seq $STARTWAIT); do
    # test if the process still exists
    if ! kill -0 $NEWPID 2>/dev/null; then
        # Process has died: get its exit code, report error, stop waiting
        wait $!
        EXITCODE=$?
        echo "Process died after restart and reported result $EXITCODE" >&2
        break
    fi
    sleep 1
done
if kill -0 $NEWPID; then
    echo "The process was started and is still alive after $STARTWAIT seconds"
    echo "so I guess it's now running correctly"
fi

내 스크립팅 솔루션에는 고유한 약점이 있습니다. nohupped 프로세스가 종료되고 다른 프로세스가 1초 내에 동일한 PID 번호를 받으면 스크립트는 더 이상 동일한 프로세스가 아니라는 것을 알 수 없습니다. (그러나 PID 번호가 그렇게 빨리 재활용된다면 더 큰 문제가 발생할 수 있습니다.)

최선의 방법으로 문제를 해결하려면 wait미리 결정된 시간에 명령을 중지한 다음 wait()모니터링되는 프로세스에서 시스템 호출을 실행하는 일종의 시간 초과 메커니즘을 설정하는 스크립트가 필요합니다(이는 wait셸 명령을 통해 수행됨). 모니터링되는 프로세스만 프로세스의 실제 상위 프로세스에서만 이 작업을 수행할 수 있기 때문입니다. 이는 쉘 스크립트로 구현하기가 매우 까다롭습니다.

관련 정보