필요한 경우 백그라운드 프로세스를 모니터링하고 종료하는 동안 백그라운드 프로세스에서 종료 코드를 얻는 안정적인 방법

필요한 경우 백그라운드 프로세스를 모니터링하고 종료하는 동안 백그라운드 프로세스에서 종료 코드를 얻는 안정적인 방법

이 작업을 수행할 것이라고 생각한 설정을 생각해 냈지만 작동하지 않습니다.

#!/bin/bash

echo "Launching a background process that may take hours to finish.."
myprog &
pid=$!
retval=
##At this time pid should hold the process id of myprog
echo "pid=${pid}"

{
    ##check if the process is still running
    psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
    killit=
    while [[ ! -z ${psl} ]]
    do
        ##if a file named "kill_flag" is detected, kill the process
        if [[ -e "kill_flag" ]]
        then
            killit=YES
            break
        fi
        #check every 3 seconds
        sleep 3
        psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
    done

    ##killit not set, normal exit, read from fd5
    if [[ -z ${killit} ]]
    then
        read <&5 retval
  else
    ##kill here, the wait will return and the sub process ends
    kill ${pid}
  fi

} 5< <( wait ${pid} > /dev/null 2>&1; echo $? )

echo "retval=$retval"

첫 번째 실행에서는 모든 것이 괜찮아 보입니다. 프로세스를 종료하여 종료할 수 있습니다. touch kill_flag그렇지 않으면 myprog가 정상적으로 완료될 때까지 기다립니다. 그러나 나는 항상 retval에서 -1을 얻는다는 것을 알았습니다. myprog는 0을 반환하며 이는 정상적인 작동으로 확인됩니다. 추가 조사를 통해 " echo $?" 부분은 wait 명령이 종료된 후가 아니라 스크립트가 시작된 직후에 실행된 것으로 나타났습니다. 나는 무슨 일이 일어나고 있는지 알고 싶습니다. 나는 bash를 처음 접했습니다.

답변1

wait현재 쉘 프로세스의 하위 프로세스에서만 작동할 수 있습니다. 내부 코드를 해석하는 서브쉘은 <(...)자매 프로세스를 기다릴 수 없습니다.

대기는 pid를 시작한 동일한 쉘 프로세스에 의해 수행되어야 합니다. zsh대신 사용하세요 bash. (다른 백그라운드 작업이 실행되고 있지 않다고 가정합니다.)

cmd & pid=$!
while (($#jobstates)) {
  [[ -e killfile ]] && kill $pid
  sleep 3
}
wait $pid; echo $?

답변2

작동하는 버전을 찾으세요:

#!/bin/bash
export retval=
##At this time pid should hold the process id of myprog
{
    ##This is the subshell that launched and monitoring myprog
    subsh=$!

    ##Since myprog is probably the only child process of this subsh, it should be pretty safe
    pid=$(ps -f --ppid ${subsh} | grep -E "\bmyprog\b" | gawk '{print $2}' )
    ##check if the process is still running
    psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
    killit=
    while [[ ! -z ${psl} ]]
    do
        ##if a file named "kill_flag" is detected, kill the process
        if [[ -e "kill_flag" ]]
        then
            killit=YES
            break
        fi
        #check every 3 seconds
        sleep 3
        psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
    done

    ##killit not set, normal exit, read from fd5
    if [[ -z ${killit} ]]
    then
        read <&5 retval
  else
    ##kill here, the wait will return and the sub process ends
    kill ${pid}
  fi

} 5< <( myprog >>logfile 2>&1; echo $? )

echo "retval=$retval"

유일한 짜증나는 점은 세마포어를 사용하여 myprog를 종료할 때 프로세스 교체가 중단되어 오류가 나타나는데 쉽게 잡힐 수 있다는 것입니다.

관련 정보