백그라운드 프로세스의 안정적인 리턴 코드


14

다음과 같은 bash 코드를 가정 해 봅시다.

foo > logfile 2>&1 &
foo_pid=$!

while ps -p$foo_pid
do
    ping -c 1 localhost
done

wait $foo_pid

if [[ $? == 0 ]]
then
    echo "foo success"
fi

$?실제로 리턴 코드가 foo아닌의 리턴 코드를 포함 한다고 가정하는 것이 안전 ping합니까? 그 질문에 대한 답이 "그렇다고 가정 할 수 없습니다." 그런 다음이 코드를 수정하여 $?항상 반환 코드가 포함 되도록하려면 어떻게해야 foo합니까?

답변:


12

으로 bash, 당신은 당신이 다른 백그라운드 작업을 시작했습니다 않는 것을 보장해야합니다 (그리고 조심 그 배경 작업을 시작할 수 있습니다 &뿐만 아니라 함께 coproc사이 및 공정의 대체와) foo &wait.

POSIX는 쉘이 최소한 25 개의 작업이 종료 된 후 종료 상태를 기억해야 하지만 bash그 이상을 기억해야합니다.

지금, 당신이 할 경우 :

foo & pid=$!
...
bar &
wait "$pid"

당신은 ( 시작 시간에 의해 종료 된 경우) bar와 동일한 pid가 제공되지 않을 것이라는 보장을 하지 않으므로 가능성이 낮더라도 종료 상태를 제공 할 수 있습니다 .foofoobarwait "$pid"bar

다음과 같이 재현 할 수 있습니다.

bash -c '(exit 12; foo) & pid=$!
         while : bar & [ "$pid" != "$!" ]; do :;done
         wait "$pid"; echo "$?"'

결국에는 0대신에 당신에게 줄 것입니다 12.

문제를 피하기 위해 한 가지 방법은 다음과 같이 작성하는 것입니다.

{
  foo_pid=$!

  while ps -p "$foo_pid"
  do
      ping -c 1 localhost
  done

  bar &
  ...

  read <&3 ret
  if [ "$ret" = 0 ]; then
    echo foo was sucessful.
  fi
} 3< <(foo > logfile 2>&1; echo "$?")

4

예, wait "$!"백그라운드 작업의 상태를 얻는 데 의존 할 수 있습니다 . 스크립트로 실행할 때 bash는 완료된 백그라운드 작업을 자동으로 수집하지 않습니다. 따라서을 실행하면 호출 wait될 때 작업이 수집됩니다 wait.

간단한 스크립트를 사용하여이를 테스트 할 수 있습니다.

#!/bin/bash
sh -c 'sleep 1; exit 22' &
sleep 5
echo "FG: $?"
wait %1
echo "BG: $?"

어느 것이 출력 될까요?

FG: 0
BG: 22

이 문장의 핵심 부분은 "스크립트로 실행할 때"의 시작이었습니다. 대화 형일 때 wait작동하지 않습니다. 프롬프트가 표시되기 직전에 프로세스가 수집되고 종료 상태가 삭제됩니다 (기본적으로).
패트릭

방금 bash 4.2.37, 4.1.2 및 3.2.48에서 시도했습니다. 그들 모두는 정확히 똑같이 동작합니다 (내 대답에 코드의 문자 복사 / 붙여 넣기). 는 wait %1백그라운드 프로세스가 "절전 5"완료 후 즉시 수집으로 "그런 일"실패합니다.
Patrick

아 알 겠어, 미안해. %1대신에 당신 을 그리워 했습니다 $!.
Stéphane Chazelas

있습니다 bash -c '(sleep 1;exit 5) & sleep 2; wait %1; echo $?'(물론 너무 비대화 형)이 그 죽은 작업의 종료 상태를 얻기 위해 실패합니다. 버그처럼 들립니다.
Stéphane Chazelas

내가 포함 할 때까지 Makefile 레시피 내에서이 기능은 작동하지 않았다 set +e. bash의 set -e함수는 잘못된 종료 코드가 발생하자마자 스크립트를 종료하는 것으로 보입니다.wait
user5359531

0

나는 당신의 가정이 맞다고 생각합니다. man bash백그라운드 프로세스 대기와 관련된 내용 은 다음과 같습니다 .

n이 존재하지 않는 프로세스 또는 작업을 지정하면 리턴 상태는 127입니다. 그렇지 않으면 리턴 상태는 마지막 프로세스 또는 대기 한 작업의 종료 상태입니다.

아마도 127을 확인해야 할 것입니다

도움이 될 수있는 것과 완전히 다른 대답을 가진 비슷한 질문이 있습니다.

Bash 스크립트는 프로세스를 기다리고 리턴 코드를 얻습니다.

편집 1

@Stephane의 의견과 답변에서 영감을 얻어 그의 대본을 확장했습니다. 약 34 개의 백그라운드 프로세스를 시작하여 느슨해지기 시작합니다.

tback

$ cat tback 
plist=()
elist=()
slist=([1]=12 [2]=15 [3]=17 [4]=19 [5]=21 [6]=23)
count=30

#start background tasksto monitor
for i in 1 2 3 4
do
  #echo pid $i ${plist[$i]} ${slist[$i]}
  (echo $BASHPID-${slist[$i]} running; exit ${slist[$i]}) & 
  plist[$i]=$!
done

echo starting $count background echos to test history
for i in `eval echo {1..$count}`
do
  echo -n "." &
  elist[$i]=$! 
done
# wait for each background echo to complete
for i in `eval echo {1..$count}`
do
  wait ${elist[$i]}
  echo -n $? 
done
echo ""
# Now wait for each monitored process and check return status with expected
failed=0
for i in 1 2 3 4
do
  wait ${plist[$i]}
  rv=$?
  echo " pid ${plist[$i]} returns $rv should be ${slist[$i]}"
  if [[ $rv != ${slist[$i]} ]] 
  then
    failed=1
  fi
done

wait
echo "Complete $failed"
if [[ $failed = "1" ]]
then
  echo Failed
else
  echo Success
fi
exit $failed
$ 

내 시스템에서

$ bash tback
14553-12 running
14554-15 running
14555-17 running
starting 30 background echos to test history
14556-19 running
..............................000000000000000000000000000000
 pid 14553 returns 12 should be 12
 pid 14554 returns 15 should be 15
 pid 14555 returns 17 should be 17
 pid 14556 returns 19 should be 19
Complete 0
Success

1
아니요, umlaute의 답변에 대한 나의 의견을보고 직접 시도해보십시오bash -c '(exit 12) & sleep 1; wait "$!"; echo "$?"'
Stéphane Chazelas

나는 bash느슨한 트랙을 보지 못했습니다 (수천 개의 작업을 시작한 후에도). 내 예제는 pid가 재사용되고 있음을 보여주었습니다.
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.