在 bash 中获取后台进程的退出状态
Get exit status of background processes in bash
我尝试了多种不同的方法来检索后台进程的退出状态:
- 捕获每个后台进程的pid,存储在一个数组中然后等待每个PID,得到每个PID的return状态并存储在一个STATUS数组中。
缺点:pid 不是此 shell
的子项
- tail --pid= -f /dev/null
缺点:此处退出状态始终为 0
在 Whosebug 上四处寻找各种答案。我仍然无法让它工作。你能帮忙告诉我哪里错了吗?
PIDS=()
STATUS=()
OVERALL_EXIT=0
# run processes and store pids in array
for target in ${target_list} ; do
./<script_to_execute> ${target} &
PIDS+=$!
done
# wait for all processes to finish and then capture return status of each
for pid in ${PIDS[@]}; do
echo "${pid}"
wait ${pid}
#tail —pid=${pid} -f /dev/null
#ps ax | grep ${pid} | grep -v grep
STATUS+=($?)
done
# looping through the status arr to check exit code for each
i=0
for st in ${STATUS[@]}; do
if [[ ${st} -ne 0 ]]; then
echo "$i failed"
OVERALL_EXIT=1
else
echo "$i finished"
fi
((i+=1))
done
exit ${overall_exit}
PIDS+=$!
...并不像您想象的那样。考虑:
PIDS=( )
PIDS+=11
PIDS+=22
PIDS+=33
declare -p PIDS
...如果您期望输出的是:
declare -a PIDS='([0]="11" [1]="22" [2]="33")
...你会错的,因为它 实际上 发出的是:
declare -a PIDS='([0]="112233")'
...因为+=
只有当右边的东西是数组时才追加一个新的数组元素。
因此,您会收到 not a child of this shell
错误,因为将所有 PID 连接成一个字符串的结果并不是实际存在的 PID。
要修复它,请使用括号:PIDS+=( "$!" )
提供一个端到端的例子:
#!/usr/bin/env bash
# run four different processes; two exit status 0, one exits status 1, on exits status 2
# ...exits happen at delays ranging between 2-5 seconds.
delays=( 5 3 2 4 )
exits=( 0 0 1 2 )
for idx in "${!delays[@]}"; do
(sleep "${delays[$idx]}"; exit "${exits[$idx]}") &
pids+=( "$!" )
done
exit_status=0
for pid in "${pids[@]}"; do
wait "$pid"; (( exit_status |= $? ))
done
echo "Combined exit status is $exit_status"
exit "$exit_status"
...5 秒后正确退出:
Combined exit status is 3
(这应该是注释,但代码格式错误)。
查看您的完整代码,您似乎正试图在 bash.
中实现 GNU Parallel 的基本版本
parallel -j0 ./<script_to_execute> ::: ${target_list}
我相信这与完整代码的作用相同(即 return 如果其中一项作业失败,则会出现错误)。
我尝试了多种不同的方法来检索后台进程的退出状态:
- 捕获每个后台进程的pid,存储在一个数组中然后等待每个PID,得到每个PID的return状态并存储在一个STATUS数组中。
缺点:pid 不是此 shell
的子项- tail --pid= -f /dev/null
缺点:此处退出状态始终为 0
在 Whosebug 上四处寻找各种答案。我仍然无法让它工作。你能帮忙告诉我哪里错了吗?
PIDS=()
STATUS=()
OVERALL_EXIT=0
# run processes and store pids in array
for target in ${target_list} ; do
./<script_to_execute> ${target} &
PIDS+=$!
done
# wait for all processes to finish and then capture return status of each
for pid in ${PIDS[@]}; do
echo "${pid}"
wait ${pid}
#tail —pid=${pid} -f /dev/null
#ps ax | grep ${pid} | grep -v grep
STATUS+=($?)
done
# looping through the status arr to check exit code for each
i=0
for st in ${STATUS[@]}; do
if [[ ${st} -ne 0 ]]; then
echo "$i failed"
OVERALL_EXIT=1
else
echo "$i finished"
fi
((i+=1))
done
exit ${overall_exit}
PIDS+=$!
...并不像您想象的那样。考虑:
PIDS=( )
PIDS+=11
PIDS+=22
PIDS+=33
declare -p PIDS
...如果您期望输出的是:
declare -a PIDS='([0]="11" [1]="22" [2]="33")
...你会错的,因为它 实际上 发出的是:
declare -a PIDS='([0]="112233")'
...因为+=
只有当右边的东西是数组时才追加一个新的数组元素。
因此,您会收到 not a child of this shell
错误,因为将所有 PID 连接成一个字符串的结果并不是实际存在的 PID。
要修复它,请使用括号:PIDS+=( "$!" )
提供一个端到端的例子:
#!/usr/bin/env bash
# run four different processes; two exit status 0, one exits status 1, on exits status 2
# ...exits happen at delays ranging between 2-5 seconds.
delays=( 5 3 2 4 )
exits=( 0 0 1 2 )
for idx in "${!delays[@]}"; do
(sleep "${delays[$idx]}"; exit "${exits[$idx]}") &
pids+=( "$!" )
done
exit_status=0
for pid in "${pids[@]}"; do
wait "$pid"; (( exit_status |= $? ))
done
echo "Combined exit status is $exit_status"
exit "$exit_status"
...5 秒后正确退出:
Combined exit status is 3
(这应该是注释,但代码格式错误)。
查看您的完整代码,您似乎正试图在 bash.
中实现 GNU Parallel 的基本版本parallel -j0 ./<script_to_execute> ::: ${target_list}
我相信这与完整代码的作用相同(即 return 如果其中一项作业失败,则会出现错误)。