多くのバックグラウンドコマンドを実行するスクリプトを作成しようとしています。各バックグラウンドコマンドに対して戻りコードを取得する必要があります。
私は次のスクリプトを試しました。
#!/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]}
私の問題は、待機ループ中に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のアプローチがより効率的になる可能性があります。