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

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

나는 그것이 작동하지 않는 것을 제외하고는 그렇게 할 것이라고 생각하는 설정을 생각해 냈습니다.

#!/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를 종료할 때 프로세스 대체가 중단되었기 때문에 오류가 발생하지만 쉽게 트랩될 수 있다는 것입니다.

관련 정보