Bash 스크립트는 프로세스를 기다리고 반환 코드를 받습니다.

Bash 스크립트는 프로세스를 기다리고 반환 코드를 받습니다.

많은 백그라운드 명령을 실행하는 스크립트를 만들려고 합니다. 각 백그라운드 명령에 대해 반환 코드를 가져와야 합니다.

나는 다음 스크립트를 시도했습니다.

 #!/bin/bash
set -x
pid=()
return=()


for i in 1 2
do
 echo start $i
 ssh mysql "/root/test$i.sh" &
 pid[$i]=$!
done

for i in ${#pid[@]}
do
echo ${pid[$i]}
wait ${pid[$i]}
return[$i]=$?

if [ ${return[$i]} -ne 0 ]
then
  echo mail error
fi

done

echo ${return[1]}
echo ${return[2]}

내 문제는 대기 루프 중에 두 번째 PID가 첫 번째 PID보다 먼저 완료되면 반환 코드를 얻을 수 없다는 것입니다.

wait pid1 pid2를 실행할 수 있다는 것을 알고 있지만 이 명령을 사용하는 모든 명령에 대한 반환 코드를 얻을 수는 없습니다.

어떤 아이디어가 있나요?

답변1

문제는 더 당신의 것입니다

for i in ${#pid[@]}

이것은 for i in 2.

그것은해야한다:

for i in 1 2

또는

for ((i = 1; i <= ${#pid[@]}; i++))

wait "$pid" ~ 할 것이다bashzsh작업이 wait시작될 때 종료된 경우에도 작업의 종료 코드를 반환하려면 (및 POSIX 셸을 사용하지만 아님)을 사용하십시오.

답변2

임시 디렉터리를 사용하여 이 작업을 수행할 수 있습니다.

# Create a temporary directory to store the statuses
dir=$(mktemp -d)

# Execute the backgrouded code. Create a file that contains the exit status.
# The filename is the PID of this group's subshell.
for i in 1 2; do
    { ssh mysql "/root/test$i.sh" ; echo "$?" > "$dir/$BASHPID" ; } &
done

# Wait for all jobs to complete
wait

# Get return information for each pid
for file in "$dir"/*; do
    printf 'PID %d returned %d\n' "${file##*/}" "$(<"$file")"
done

# Remove the temporary directory
rm -r "$dir"

답변3

임시 파일의 보편적인 구현은 없습니다.

#!/usr/bin/env bash

## associative array for job status
declare -A JOBS

## run command in the background
background() {
  eval $1 & JOBS[$!]="$1"
}

## check exit status of each job
## preserve exit status in ${JOBS}
## returns 1 if any job failed
reap() {
  local cmd
  local status=0
  for pid in ${!JOBS[@]}; do
    cmd=${JOBS[${pid}]}
    wait ${pid} ; JOBS[${pid}]=$?
    if [[ ${JOBS[${pid}]} -ne 0 ]]; then
      status=${JOBS[${pid}]}
      echo -e "[${pid}] Exited with status: ${status}\n${cmd}"
    fi
  done
  return ${status}
}

background 'sleep 1 ; false'
background 'sleep 3 ; true'
background 'sleep 2 ; exit 5'
background 'sleep 5 ; true'

reap || echo "Ooops! Some jobs failed"

답변4

Stéphane의 답변은 좋지만 나는 더 선호합니다

for i in ${!pid[@]}
do
    wait "${pid[i]}"
    return_status[i]=$?
    unset "pid[$i]"
done

어떤 항목이 아직 있는지에 관계없이 배열의 키를 반복하므로 pid이를 조정하고 루프를 중단한 다음 전체 루프를 다시 시작하면 정상적으로 작동합니다. 그리고 i애당초 연속된 값이 필요하지 않습니다.

물론 수천 개의 프로세스를 처리하는 경우 비희소 목록이 있을 때 Stépane의 접근 방식이 더 효율적일 수 있습니다.

관련 정보