获取bash中后台进程的退出状态

时间:2018-08-10 22:39:22

标签: bash parallel-processing background-process exit-code

我尝试了多种不同的方法来检索后台进程的退出状态:

  1. 捕获每个后台进程的pid,存储在数组中,然后等待每个PID,获取每个PID的返回状态,并存储在STATUS数组中。

骗局:pid不是该shell的子代

  1. tail --pid = -f / dev / null

缺点:此处的退出状态始终为0

寻找关于stackoverflow的各种答案。我仍然无法正常工作。您能帮忙,让我知道我要去哪里了吗?

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}

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:1)

(这应该是注释,但是代码格式错误)。

查看完整的代码,似乎您正在尝试在bash中实现GNU Parallel的基本版本。

parallel -j0 ./<script_to_execute> ::: ${target_list}

我相信这将与完整代码相同(即,如果其中一项作业失败,则返回错误)。