많은 백그라운드 명령을 실행하는 스크립트를 만들려고 합니다. 각 백그라운드 명령에 대해 반환 코드를 가져와야 합니다.
나는 다음 스크립트를 시도했습니다.
#!/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"
~ 할 것이다bash
zsh
작업이 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의 접근 방식이 더 효율적일 수 있습니다.