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

Bash脚本中如何等待所有后台进程完成?wait命令失效问题

如何等待所有嵌套的后台工作进程完成?

问题背景

需要并发运行2个工作负载,每个工作负载后台启动,且每个负载包含3个后台运行的run_sleep.sh进程。期望所有进程完成后再执行后续逻辑,但现有脚本要么直接返回,要么无法正确等待所有进程。

现有脚本的问题

脚本1的问题

for wl_num in 1 2 ; do
  echo "... Workload $wl_num"
  {
    for i in `seq 1 3` ; do
      echo ...... workload process $i
      . run_sleep.sh 300 &
    done 
  } &
done
wait
echo ... done waiting for both workloads

这里的wait仅会等待外层的2个子shell(即{...}&启动的进程),但子shell内部启动的run_sleep.sh &进程并不会被主shell的wait追踪。子shell执行完内部的for循环后就会退出,里面的后台进程变成孤儿进程,主脚本的wait执行完就直接继续后续逻辑,不会等这些孤儿进程。

脚本2的问题

for wl_num in 1 2 ; do
  echo "... Workload $wl_num"
  {
    for i in `seq 1 3` ; do
      echo ...... workload process $i
      . run_sleep.sh 5 &
      pids[${i}=$!  
    done 
  } & 
  wlpids[${db_num}]=$!
done
for pid in ${pids[*]} ; do
  wait $pid
done
for pid in ${wlpids[*]} ; do
  wait $pid
done
echo ... done waiting for both workloads
  1. 语法错误:pids[${i}=$!缺少闭合的],db_num变量未定义;
  2. 逻辑错误:子shell({...}&)内部定义的pids数组无法被主shell访问,因为子shell有独立的进程空间,变量不会共享,所以主shell的pids数组是空的,无法等待内部进程。

解决方案

方案1:在主shell中记录所有进程的PID

直接在主循环里启动所有后台进程,把每个进程的PID都记录到主shell的数组中,最后统一wait所有PID:

# 初始化PID数组
pids=()

for wl_num in 1 2 ; do
  echo "... Workload $wl_num"
  for i in `seq 1 3` ; do
    echo ...... workload process $i
    . run_sleep.sh 300 &
    # 将每个后台进程的PID加入数组
    pids+=($!)
  done
done

# 等待所有记录的PID完成
for pid in "${pids[@]}" ; do
  wait $pid
done

echo ... done waiting for all processes

这个方法最直接,所有进程的PID都在主shell中追踪,确保不会遗漏任何进程。

方案2:让子shell内部等待自身的后台进程

如果必须保留工作负载的子shell结构,可以让每个子shell内部先等待自己启动的所有进程完成,这样主shell等待子shell即可:

# 初始化工作负载子shell的PID数组
wlpids=()

for wl_num in 1 2 ; do
  echo "... Workload $wl_num"
  {
    # 子shell内部的PID数组
    local sub_pids=()
    for i in `seq 1 3` ; do
      echo ...... workload process $i
      . run_sleep.sh 300 &
      sub_pids+=($!)
    done
    # 子shell内部等待所有自身启动的进程
    for pid in "${sub_pids[@]}" ; do
      wait $pid
    done
  } &
  # 记录子shell的PID
  wlpids+=($!)
done

# 主shell等待所有工作负载子shell完成
for pid in "${wlpids[@]}" ; do
  wait $pid
done

echo ... done waiting for both workloads and all their processes

这里每个子shell会先等自己内部的所有后台进程完成后才退出,所以主shell等待子shell就等同于等待该负载下的所有进程完成。

注意事项

  • 不要在子shell中定义需要主shell访问的变量,子shell的变量无法传递回主shell;
  • 使用"${array[@]}"而不是${array[*]}来遍历数组,避免PID包含特殊字符时出现问题;
  • 如果run_sleep.sh是独立脚本,使用./run_sleep.sh而不是. run_sleep.sh(后者是source,会在当前shell执行,可能影响变量环境),如果确实需要source,确保脚本没有退出逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 22:43:15