wait同步后台任务的核心是“启动记PID、等待选策略、退出查状态”:用&启动异步任务,$!捕获PID,wait控制节奏;支持wait(全等)、wait -n(任一)、wait $p1 $p2(指定)三种模式;需逐个wait并读取$?获取真实退出码;建议加wait -t超时和kill清理。

用 wait 同步多个后台子任务,核心是“启动时记 PID、等待时选策略、退出后查状态”。它不负责并发执行,只做等待和状态反馈,真正靠 & 启动异步,靠 $! 捕获 PID,再用 wait 控制节奏。
启动后台任务并准确记录每个 PID
每条带 & 的命令执行后,必须立刻用 $! 保存它的进程号。否则后续命令会覆盖 $!,导致 PID 丢失:
sleep 4 & PID1=$!./backup.sh & PID2=$!curl -s http://api/health & PID3=$!
避免用 %1 这类作业号——它依赖当前 shell 的 job table,在脚本中不稳定,尤其跨函数或子 shell 时容易失效。
按需选择等待方式:全部、任一或指定几个
wait 支持三种典型模式,对应不同编排逻辑:
- 等全部完成:
wait(不加参数),脚本停在这里直到所有已记录的后台进程结束 - 等任意一个先完成:
wait -n(Bash 4.3+),返回第一个结束进程的退出码,适合“谁先好谁先用”场景 - 等指定几个完成:
wait $PID1 $PID2,只阻塞到这两个结束,其余继续运行,适合分组同步
例如:想等数据库备份和日志归档都做完才发通知,但监控检查可以单独等超时,就分开调用 wait $PID_BACKUP $PID_ARCHIVE 和带 -t 的监控等待。
获取真实退出状态,不能只靠 wait 返回值
wait 自身的退出码只表示“是否等到了”,不是子进程的结果。要判断某个任务成败,必须对每个 PID 单独 wait 并读取 $?:
wait $PID1; code1=$?wait $PID2; code2=$?- 然后用
if [ $code1 -ne 0 ] || [ $code2 -ne 0 ]; then ...做汇总判断
直接 wait 后查 $? 得到的是最后一个结束进程的状态,无法反映全部情况。
加超时和清理,避免脚本卡死
生产环境必须防止单个慢任务拖垮整个流程。Bash 4.3+ 可用 wait -t 秒数 $PID:
if ! wait -t 30 $PID_FETCH; then echo "数据拉取超时"; kill $PID_FETCH 2>/dev/null; exit 1; fi- 旧版 Bash 可用
timeout 30s bash -c 'wait $1' _ $PID_FETCH,但注意timeout杀的是子 shell,不一定传信号给目标进程 - 超时后务必
kill或kill -9清理残留,防止僵尸或孤儿进程堆积
不复杂但容易忽略。











