最可靠方式是通过readlink -f /proc//exe获取进程绝对路径,因ps仅显示命令名,which/whereis依赖当前环境且不覆盖虚拟环境或自定义路径;辅以/proc//cmdline和/proc//cwd可完整还原运行上下文。

/proc/PID/exe 是唯一能拿到真实可执行路径的入口,其他方式(ps、which、whereis)全都不靠谱。
为什么 ps -o args 或 ps -ef 不能信
它只显示命令行启动时的“名字”,比如 python 或 node,根本不管实际跑的是 /home/user/.pyenv/versions/3.11.9/bin/python 还是 /opt/node-v20/bin/node。尤其在用 pyenv、conda、nvm 或自定义 PATH 时,ps 输出和真实二进制完全脱钩。
-
ps -p 1234 -o comm,args可能输出python /app/main.py,但你没法知道这个python到底是哪个 - 如果进程是用绝对路径启动的(如
/opt/myapp/bin/runner),ps有时反而只显示runner,丢掉前缀 - 脚本类进程(bash/sh)更危险:
ps显示/bin/bash,但真正逻辑在/etc/init.d/myapp里——得靠/proc/PID/cmdline补全
怎么用 /proc/PID/exe 拿到绝对路径
这是内核维护的符号链接,指向进程加载的原始二进制或解释器,不受环境变量、别名、PATH 干扰。
- 先拿到 PID:
pgrep -f "myapp"或ps aux | grep myapp - 直接解析路径:
readlink -f /proc/1234/exe(推荐,一步到位) - 或看软链本身:
ls -l /proc/1234/exe,输出形如/proc/1234/exe -> /usr/local/bin/nginx - 如果看到
(deleted)后缀,说明文件已被删但进程还在跑,路径仍有效,只是磁盘上没了
光看 exe 不够:cmdline 和 cwd 得一起查
/proc/PID/exe 告诉你“程序本体在哪”,但运行行为还取决于“它被怎么调用”和“它在哪起家”。这三者缺一不可:
-
cat /proc/1234/cmdline | tr '\0' ' '—— 看完整启动参数,比如java -jar /opt/app.jar --config /etc/app.conf -
pwdx 1234或ls -l /proc/1234/cwd—— 查工作目录,很多程序相对路径配置(如./conf/app.yml)依赖这个 - 对 Python/Node.js 类进程,
exe指向解释器,cmdline才暴露真实脚本路径,cwd决定模块导入根目录
哪些方法会误导你,务必避开
which 和 whereis 完全是另一套逻辑,跟正在运行的进程毫无关系。
-
which python查当前 shell 的$PATH,不是进程启动时的 PATH;进程可能用了不同 shell、不同用户、甚至修改过environ -
whereis python只扫系统数据库(/usr/bin、/usr/share/man等),漏掉/opt、~/.local/bin、容器内路径 -
lsof -p 1234可能列出txt类型的可执行文件,但结果不稳定:有些进程不保持txtfd,或者被 ptrace 暂停后lsof就读不到 -
ps的-o pid,comm,args字段在某些内核版本或容器环境下会被截断,参数不全
/proc/PID/exe 对权限敏感——普通用户查不了其他用户的进程,sudo 不是万能解,有些 systemd 服务启用了 ProtectProc 或 RestrictSUIDSGID,连 root 都读不到 exe。这时候只能退回到 systemctl status xxx.service 看 ExecStart=,或检查 /proc/PID/environ 里有没有线索。











