如何在Shell中让命令获取自身PID并作为命令行参数传入?
获取当前执行命令自身的PID(而非Shell进程PID)
我在Shell脚本或交互场景中,有时需要获取当前运行命令自身的进程ID(PID),并把这个PID作为参数传给该命令。比如期望实现这样的效果:
% /bin/echo I am process $WHATEVER I am process 123
这里要打印的是echo进程自己的PID,而不是启动它的bash进程的PID。
常见错误尝试
用$$变量(无效)
$$代表的是Shell自身的PID,哪怕每次都启动新的echo进程,输出的数字也不会变:
% /bin/echo $$ 1234 % /bin/echo $$ 1234
(注:这里调用/bin/echo是为了确保它作为独立进程运行,而非Shell内置的echo命令)
显式创建子shell(仍无法获取命令PID)
就算用子shell包裹命令,$$也会被特殊处理,返回的还是父Shell的PID:
% (/bin/echo $$) 1234
bash有个扩展变量$BASHPID,能获取子shell的PID,但这也不是echo命令自身的PID:
% (/bin/echo $BASHPID) 9784
可行解决方案
因为Shell会先展开变量再fork新进程,所以没法直接用一个类似$WHATEVER的变量直接获取新进程的PID。但可以通过以下方式实现需求:
方法1:子shell+exec替换进程(简洁可靠)
利用子shell启动后,用exec让目标命令替换掉子shell进程,此时$BASHPID就会是目标命令的PID:
% (exec /bin/echo I am process $BASHPID) I am process 5678
原理是子shell启动后,exec会用/bin/echo覆盖当前子shell进程,此时$BASHPID对应的就是echo进程的PID。
方法2:临时文件传递PID(适合脚本场景)
如果是在脚本中,可以通过后台进程+临时文件的方式传递PID:
#!/bin/bash temp_pid=$(mktemp) # 启动后台进程,读取临时文件中的PID /bin/echo I am process $(cat $temp_pid) & # 将后台进程的PID写入临时文件 echo $! > $temp_pid # 等待进程执行完成 wait # 清理临时文件 rm $temp_pid
这种方法适合脚本场景,但交互使用不如第一种简洁。
方法3:用ps实时查找(不推荐)
可以尝试在命令执行瞬间用ps查找PID,但这种方法存在竞态条件,如果同一时间有多个同名进程运行,结果会不准确:
% /bin/echo I am process $(ps -o pid= -C echo | tail -n1)
内容的提问来源于stack exchange,提问作者Ed Avis
相关产品推荐
相关产品推荐

