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

编写init.d脚本时保存forked进程PID出现不一致问题

为什么sudo启动的进程$!捕获的PID和实际java进程PID不一致?

问题描述

我正在编写init.d脚本,遇到了保存forked进程PID的问题。以下是我的脚本片段:

sudo -u $USER nohup -- nice -n "0" java Test >> /dev/null 2>&1 < /dev/null & NEWPID="$!" echo $NEWPID

运行该脚本后输出的PID为4595,但执行ps | grep java得到的java进程PID是4596,二者不一致。而直接执行java Test & NEWPID="$!" echo $NEWPID时,输出的PID与ps查询结果一致。请问第一种写法存在什么问题?


问题原因

你碰到的核心问题是**$!捕获的是sudo进程的PID,而不是最终java进程的PID**,整个命令的执行链是这样的:

  1. 当你在命令末尾加&时,后台启动的是最外层的sudo进程(也就是你看到的4595)
  2. sudo会创建新进程切换到指定用户,然后启动nohup
  3. nohup接着执行nice,最后nice启动目标java进程(PID 4596)

而直接运行java Test &时,没有中间的sudo/nohup/nice这些包装进程,$!直接对应java进程本身的PID,所以和ps结果完全匹配。

解决办法

要正确捕获java进程的PID,你需要让sudo执行一个子shell,在子shell内部处理后台启动逻辑,这样$!就能拿到真正的java相关PID:

直接输出PID

sudo -u $USER bash -c 'nohup nice -n 0 java Test >> /dev/null 2>&1 < /dev/null & echo $!'

保存PID到文件(init.d脚本常用方式)

sudo -u $USER bash -c 'nohup nice -n 0 java Test >> /dev/null 2>&1 < /dev/null & echo $! > /var/run/test.pid'

这里的关键逻辑是:

  • bash -c创建的子shell会在目标用户环境下执行命令,$!在子shell中捕获的是nohup进程的PID
  • 而nohup和nice都是通过exec调用后续命令的,它们不会保留自身进程,最终这个PID会直接对应到java进程

另外补充一点:你脚本里的nohup --是多余的,因为nice没有需要用--分隔的参数,去掉也不会影响功能。


内容的提问来源于stack exchange,提问作者Some Name

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:17:19