为何Bash会“遗忘”我的后台进程?
bash批量后台进程wait报错问题分析
问题重现
编写的脚本如下:
#!/bin/bash pids=() for i in $(seq 1 999); do sleep 1 & pids+=( "$!" ) done for pid in "${pids[@]}"; do wait "$pid" done
执行时反复出现类似错误:
./foo.sh: line 8: wait: pid 24752 is not a child of this shell
错误共出现171次,但将循环次数改为50时无报错,环境为Windows下的GNU bash 4.4.23。
原因解析
sleep 1 &会创建一个仅运行1秒就退出的后台进程。- 创建999个进程的循环虽快,但仍需要时间完成全部迭代。在循环还没跑完时,最早启动的一批
sleep已经执行完毕并退出,bash会自动回收这些已退出子进程的状态,这些PID不再属于当前shell的活跃子进程。 - 当第二个循环执行
wait "$pid"时,对已被回收的PID执行等待操作,就会触发“不是当前shell子进程”的错误。 - 循环次数改为50时,整个循环跑完的时间远小于1秒,所有
sleep都还在运行,wait操作针对的都是活跃子进程,因此不会报错。
解决办法
如果要确保所有后台进程完成且不报错,直接用不带参数的wait即可,它会等待当前shell的所有子进程结束,无需手动记录PID:
#!/bin/bash for i in $(seq 1 999); do sleep 1 & done wait
内容的提问来源于stack exchange,提问作者Dragon
相关产品推荐
相关产品推荐

