Bash脚本中wait命令不等待管道循环内后台任务的问题咨询
原因说明
- Bash 默认执行管道
command1 | command2时,管道的每一段命令都会运行在独立的子shell进程中,和主脚本的进程环境完全隔离。你第二个脚本中的while read循环属于管道右侧的命令,因此整个循环的所有操作都在子shell内完成。 - 在子shell中执行的
sleep 9 &后台任务,父进程是子shell的PID,不会被加入主脚本的后台任务列表。 wait命令的作用范围仅限当前shell环境下启动的后台子进程,无法感知其他子shell中启动的后台任务。主脚本执行wait时,检测到当前没有自己启动的后台任务,就会直接跳过,立即执行后续的echo "ok"。- 管道执行完成后,运行
while循环的子shell会直接退出,它启动的sleep进程会被系统的init进程领养,和主脚本彻底脱离关联。
修复方案
如果你需要wait能正确等待循环中启动的后台任务,可以用两种方法规避管道子shell的问题:
方法1:用进程替换替代管道
将输入通过进程替换重定向给while循环,让循环运行在主shell环境中:
#!/bin/bash while read in do sleep 9 & done < <(echo "1") wait echo "ok"
方法2:开启lastpipe选项(Bash 4.2+支持)
开启lastpipe配置后,管道的最后一段命令会直接在当前shell执行,不需要fork子shell:
#!/bin/bash shopt -s lastpipe echo "1" | while read in do sleep 9 & done wait echo "ok"
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

