[bash] 하위 프로세스가 코드! = 0으로 끝날 때 여러 하위 프로세스가 종료되고 종료 코드! = 0을 반환하기 위해 bash에서 대기하는 방법은 무엇입니까?

하위 프로세스 중 하나가 코드! = 0로 끝나는 경우 해당 스크립트에서 생성 된 여러 하위 프로세스가 종료 코드! = 0을 반환하도록 bash 스크립트에서 대기하는 방법

간단한 스크립트 :

#!/bin/bash
for i in `seq 0 9`; do
  doCalculations $i &
done
wait

위의 스크립트는 생성 된 10 개의 하위 프로세스를 모두 기다리지 만 종료 상태는 항상 0입니다 (참조 help wait). 이 스크립트를 수정하여 생성 된 하위 프로세스의 종료 상태를 발견하고 하위 프로세스 중 하나가 코드! = 0으로 끝나면 종료 코드 1을 반환하도록하려면 어떻게해야합니까?

서브 프로세스의 PID를 수집하는 것보다 더 나은 해결책이 있습니까? 순서대로 기다렸다가 종료 상태를 합산합니까?



답변

wait또한 (선택적으로) 프로세스의 PID를 기다리며 $! 백그라운드에서 시작된 마지막 명령의 PID를 얻습니다. 생성 된 각 하위 프로세스의 PID를 배열에 저장하도록 루프를 수정 한 다음 각 PID에서 다시 대기합니다.

# run processes and store pids in array
for i in $n_procs; do
    ./procs[${i}] &
    pids[${i}]=$!
done

# wait for all pids
for pid in ${pids[*]}; do
    wait $pid
done


답변

http://jeremy.zawodny.com/blog/archives/010717.html :

#!/bin/bash

FAIL=0

echo "starting"

./sleeper 2 0 &
./sleeper 2 1 &
./sleeper 3 0 &
./sleeper 2 0 &

for job in `jobs -p`
do
echo $job
    wait $job || let "FAIL+=1"
done

echo $FAIL

if [ "$FAIL" == "0" ];
then
echo "YAY!"
else
echo "FAIL! ($FAIL)"
fi


답변

다음은를 사용하는 간단한 예 wait입니다.

일부 프로세스를 실행하십시오.

$ sleep 10 &
$ sleep 10 &
$ sleep 20 &
$ sleep 20 &

그런 다음 wait명령으로 기다리십시오 .

$ wait < <(jobs -p)

또는 wait모두를 위해 (논쟁없이).

백그라운드의 모든 작업이 완료 될 때까지 기다립니다.

경우 -n옵션이 제공되어, 다음 작업에 대한 대기 종료 및 종료 상태를 반환합니다.

help waithelp jobs구문을 참조하십시오 .

그러나 단점은 마지막 ID의 상태에서만 반환되므로 각 하위 프로세스의 상태를 확인하여 변수에 저장해야한다는 것입니다.

또는 계산 기능을 사용하여 오류 발생시 (빈 또는 실패한 로그가있는) 일부 파일을 생성 한 다음 해당 파일이 존재하는지 확인

$ sleep 20 && true || tee fail &
$ sleep 20 && false || tee fail &
$ wait < <(jobs -p)
$ test -f fail && echo Calculation failed.


답변

GNU Parallel이 설치되어 있다면 다음을 수행 할 수 있습니다.

# If doCalculations is a function
export -f doCalculations
seq 0 9 | parallel doCalculations {}

GNU Parallel은 종료 코드를 제공합니다.

  • 0-모든 작업이 오류없이 실행되었습니다.

  • 1-253-일부 작업이 실패했습니다. 종료 상태는 실패한 작업 수를 제공합니다.

  • 254-253 개 이상의 작업이 실패했습니다.

  • 255-기타 오류

자세한 내용은 소개 비디오를 참조하십시오 : http://pi.dk/1


답변

어떻습니까?

#!/bin/bash

pids=""

for i in `seq 0 9`; do
   doCalculations $i &
   pids="$pids $!"
done

wait $pids

...code continued here ...

최신 정보:

여러 의견 제시자가 지적한 것처럼 위의 과정은 계속하기 전에 모든 프로세스가 완료되기를 기다립니다.하지만 프로세스 중 하나가 실패하면 종료하지 않고 실패하지 않습니다. :

#!/bin/bash

pids=""
RESULT=0


for i in `seq 0 9`; do
   doCalculations $i &
   pids="$pids $!"
done

for pid in $pids; do
    wait $pid || let "RESULT=1"
done

if [ "$RESULT" == "1" ];
    then
       exit 1
fi

...code continued here ...


답변

지금까지 내가 생각해 낸 내용은 다음과 같습니다. 아이가 종료되면 잠자기 명령을 중단하여 WAITALL_DELAY사용법 에 맞출 필요가 없도록하는 방법을 알고 싶습니다 .

waitall() { # PID...
  ## Wait for children to exit and indicate whether all exited with 0 status.
  local errors=0
  while :; do
    debug "Processes remaining: $*"
    for pid in "$@"; do
      shift
      if kill -0 "$pid" 2>/dev/null; then
        debug "$pid is still alive."
        set -- "$@" "$pid"
      elif wait "$pid"; then
        debug "$pid exited with zero exit status."
      else
        debug "$pid exited with non-zero exit status."
        ((++errors))
      fi
    done
    (("$#" > 0)) || break
    # TODO: how to interrupt this sleep when a child terminates?
    sleep ${WAITALL_DELAY:-1}
   done
  ((errors == 0))
}

debug() { echo "DEBUG: $*" >&2; }

pids=""
for t in 3 5 4; do
  sleep "$t" &
  pids="$pids $!"
done
waitall $pids


답변

이것을 병렬화하려면 …

for i in $(whatever_list) ; do
   do_something $i
done

이것을 번역하십시오 …

for i in $(whatever_list) ; do echo $i ; done | ## execute in parallel...
   (
   export -f do_something ## export functions (if needed)
   export PATH ## export any variables that are required
   xargs -I{} --max-procs 0 bash -c ' ## process in batches...
      {
      echo "processing {}" ## optional
      do_something {}
      }'
   )
  • 한 프로세스에서 오류가 발생 하면 다른 프로세스를 방해하지 않지만 시퀀스에서 전체적으로 종료 코드가 0이 아닙니다 .
  • 특정 경우에 함수 및 변수 내보내기가 필요할 수도 있고 필요하지 않을 수도 있습니다.
  • --max-procs원하는 병렬 처리량을 기준으로 설정할 수 있습니다 ( 0“한 번에 모두”를 의미 함).
  • GNU Parallel 은 대신 사용되는 몇 가지 추가 기능을 제공 xargs하지만 항상 기본적으로 설치되는 것은 아닙니다.
  • for때문에 루프는이 예에서 꼭 필요한 것은 echo $i근본적으로 단지 출력을 재생한다 $(whatever_list). for키워드를 사용하면 현재 상황을 좀 더 쉽게 알 수 있다고 생각합니다 .
  • 배쉬 문자열 처리는 혼란 스러울 수 있습니다. 작은 따옴표를 사용하면 사소한 스크립트를 래핑하는 데 가장 효과적이라는 것을 알았습니다.
  • Bash 병렬 처리에 대한보다 직접적인 접근 방식과 달리 전체 작업 (^ C 또는 유사 항목 사용)을 쉽게 중단 할 수 있습니다 .

간단한 작업 예는 다음과 같습니다.

for i in {0..5} ; do echo $i ; done |xargs -I{} --max-procs 2 bash -c '
   {
   echo sleep {}
   sleep 2s
   }'