You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

子进程执行失败时如何退出Shell父脚本及循环

解决Shell父脚本等待所有子进程并检查退出状态的方案

这个需求在日常Shell脚本开发里挺常见的——既要混合运行前台和后台子脚本,还要确保所有子进程完成后统一检查状态,一旦有失败就立刻终止父脚本。下面我给你一套清晰的实现思路和完整代码:

核心思路

  1. 区分前台/后台脚本处理:
    • 前台脚本:直接执行,执行完成后立即检查退出状态,失败则直接终止父脚本(同时清理已启动的后台进程)。
    • 后台脚本:启动后收集其PID到数组中,等所有前台脚本执行完后,统一等待这些后台进程并逐个检查状态。
  2. 统一状态检查:不管是前台还是后台脚本,只要有一个执行失败(退出状态非0),父脚本最终就以失败状态退出。

完整示例代码

#!/bin/bash

# 初始化存储后台进程PID的数组
declare -a pids

# 可选:添加信号捕获,父脚本被中断时清理后台进程
trap 'echo "Parent script interrupted! Cleaning up background processes..."; kill "${pids[@]}" 2>/dev/null; exit 1' INT TERM

# 循环遍历要执行的子脚本列表
for script in "child_foreground_1.sh" "child_background_1.sh" "child_foreground_2.sh" "child_background_2.sh"; do
    if [[ "$script" == *"background"* ]]; then
        # 处理后台运行的子脚本
        ./"$script" &
        local pid=$!
        pids+=("$pid")
        echo "Launched background script: $script (PID: $pid)"
    else
        # 处理前台运行的子脚本
        echo "Running foreground script: $script..."
        ./"$script"
        local status=$?
        if [[ $status -ne 0 ]]; then
            echo "ERROR: Foreground script $script failed with exit status $status!"
            echo "Cleaning up running background processes..."
            kill "${pids[@]}" 2>/dev/null
            exit $status
        fi
        echo "Foreground script $script completed successfully."
    fi
done

# 等待所有后台进程完成并检查状态
echo "Waiting for all background processes to finish..."
local global_exit_status=0
for pid in "${pids[@]}"; do
    wait "$pid"
    local status=$?
    if [[ $status -ne 0 ]]; then
        echo "ERROR: Background process (PID: $pid) failed with exit status $status!"
        global_exit_status=$status
    else
        echo "Background process (PID: $pid) completed successfully."
    fi
done

# 根据全局状态决定父脚本退出码
if [[ $global_exit_status -ne 0 ]]; then
    echo "One or more scripts failed. Parent script exiting with status $global_exit_status."
    exit $global_exit_status
fi

echo "All scripts executed successfully!"
exit 0

关键细节说明

  • PID数组管理:用declare -a pids声明数组,每次启动后台脚本后把$!(最近后台进程的PID)加入数组。
  • 前台脚本失败处理:前台脚本执行后立即检查$?,如果失败,先用kill "${pids[@]}"杀掉所有已启动的后台进程(2>/dev/null避免进程已结束时的报错),然后父脚本退出对应状态。
  • 后台进程等待与检查:用wait "$pid"逐个等待后台进程,wait命令会返回该进程的退出状态,我们可以直接捕获并判断。
  • 信号捕获:添加trap命令处理INT(Ctrl+C)和TERM(终止信号),避免父脚本被中断后留下孤儿进程。

注意事项

  • 确保所有子脚本在执行失败时正确返回非0的退出码,否则父脚本无法识别失败情况。
  • 如果你的子脚本名称没有统一的标识(比如示例中的background关键词),可以改成用列表单独区分前台/后台脚本,比如:
    foreground_scripts=("child1.sh" "child3.sh")
    background_scripts=("child2.sh" "child4.sh")
    
    然后分别遍历这两个列表处理。

内容的提问来源于stack exchange,提问作者Joha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:59:46