Bash脚本等待后台进程PID时报错:pid 1不是当前shell的子进程
解决Bash脚本中
wait报错:pid 1 is not a child of this shell的问题 这个报错的核心原因有两个,咱们一步步拆解:
问题根源
混淆了Shell Job编号与系统PID
你用jobs %%获取的是当前Shell内部的job编号(比如输出里的[1]),而不是进程的真实系统PID。getJobId提取的这个编号传给wait后,Shell会尝试等待对应job,但如果进程已经脱离当前Shell,就会找不到目标进程。nohup导致进程脱离当前Shellnohup的设计目的是让进程在Shell退出后继续运行,它会把进程与当前会话分离,使得进程的父进程变为系统的init进程(PID 1)。此时当前Shell不再是该进程的父进程,自然无法用wait等待它。
解决方案
方案1:移除nohup,直接捕获后台进程PID(推荐)
既然你需要在脚本中等待进程完成,nohup完全是多余的——脚本会一直运行到wait结束,进程不会被意外终止。直接用$!获取后台进程的真实PID即可,这是当前Shell的直接子进程,wait可以正常处理:
# 用数组存储PID(比字符串更健壮,避免空格/特殊字符问题) jobsList=() function deploy(){ echo "Building now" # 移除nohup,直接后台运行并捕获PID docker-compose build "$1" &>> logs/"$2".txt & lastJob=$! # $! 会返回最后一个后台进程的真实PID echo "lastjob is --- $lastJob" jobsList+=("$lastJob") # 将PID添加到数组 } # (这里需要补充你调用deploy的逻辑,比如:deploy service1 service1-build) for job in "${jobsList[@]}" do wait "$job" exit_code=$? if [[ "$exit_code" != 0 ]]; then handleError fi done
方案2:如果必须保留nohup(不推荐)
如果你确实需要nohup(比如担心脚本意外中断),可以用子Shell包裹命令并捕获PID,但依然要注意进程脱离的风险:
jobsList=() function deploy(){ echo "Building now" # 用子Shell包裹nohup命令,捕获PID (nohup docker-compose build "$1" &>> logs/"$2".txt &) lastJob=$! echo "lastjob is --- $lastJob" jobsList+=("$lastJob") }
额外优化建议
- 使用数组存储PID:避免字符串拼接带来的空格、特殊字符问题,
jobsList=()和jobsList+=("$lastJob")是更健壮的写法。 - 给变量加引号:比如
docker-compose build "$1"和logs/"$2".txt,防止参数或文件名包含空格时出错。 - 放弃
jobs命令依赖:jobs是Shell内部的job管理命令,依赖当前Shell上下文,而$!直接获取PID,更可靠。
内容的提问来源于stack exchange,提问作者relentless-coder
相关产品推荐
相关产品推荐

