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

Bash脚本等待后台进程PID时报错:pid 1不是当前shell的子进程

解决Bash脚本中wait报错:pid 1 is not a child of this shell的问题

这个报错的核心原因有两个,咱们一步步拆解:

问题根源

  1. 混淆了Shell Job编号与系统PID
    你用jobs %%获取的是当前Shell内部的job编号(比如输出里的[1]),而不是进程的真实系统PID。getJobId提取的这个编号传给wait后,Shell会尝试等待对应job,但如果进程已经脱离当前Shell,就会找不到目标进程。

  2. nohup导致进程脱离当前Shell
    nohup的设计目的是让进程在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:39:18