从Python中查找Linux中特定PID的命令

10 投票
7 回答
10666 浏览
提问于 2025-04-15 14:23

我想知道有没有办法找到一个进程ID(PID)对应的“命令”。这里的“命令”指的是你在Linux命令行中运行“top”命令时看到的最后一列内容。我希望能通过Python获取这个信息,当我有一个特定的PID时。

任何帮助都非常感谢。谢谢。

7 个回答

7

你可以查看 /proc/$PID/cmdline,然后对 /proc/$PID/exe 使用 os.readlink()。

/proc/$PID/cmdline 的内容不一定是准确的,因为程序可以改变它的参数,或者可能没有完整的路径。以下是我当前进程列表中的三个例子:

  • avahi-daemon: chroot helper
  • qmgr -l -t fifo -u
  • /usr/sbin/postgrey --pidfile=/var/run/postgrey.pid --daemonize --inet=127.0.0.1:60000 --delay=55

第一个例子很明显——这不是一个有效的路径或程序名。第二个只是一个没有路径名的可执行文件。第三个看起来还不错,但整个命令行其实在 argv[0] 中,参数之间用空格分隔。通常情况下,参数应该是用 NUL 分隔的。

这些都说明了 /proc/$PID/cmdline(或者 ps(1) 的输出)并不可靠。

不过,/proc/$PID/exe 也不一定可靠。通常它是指向可执行文件的符号链接,这个文件是进程的主要文本段。但有时候,如果可执行文件不再存在于文件系统中,它后面会有 " (deleted)" 的标记。

此外,文本段的程序不一定是你想要的。例如,上面提到的 /usr/sbin/postgrey/proc/$PID/exe 实际上是 /usr/bin/perl。所有解释型脚本(以 #! 开头)都是这样的情况。

我决定解析 /proc/$PID/cmdline——取向量的第一个元素,然后查找其中的空格,取第一个空格之前的部分。如果那是一个可执行文件,我就停在那里。否则,我会对 /proc/$PID/exe 使用 readlink(2),并去掉末尾的 " (deleted)" 字符串。如果可执行文件名中有空格,这个方法就会失败。对此你也没什么办法。

顺便说一下,使用 ps(1) 而不是 /proc/$PID/cmdline 的建议在这种情况下不适用,因为你最终还是要回到 /proc/$PID/exe。你会依赖于 /proc 文件系统,所以不如直接用 read(2) 来读取,而不是用 pipe(2)、fork(2)、execve(2)、readdir(3)...、write(2)、read(2)。虽然从 Python 代码的角度来看,ps 和 /proc/$PID/cmdline 可能是一样的,但在 ps 背后有很多其他的事情在发生。

8

一个有趣的Python库叫做 psutil

比如说,如果你想获取某个特定进程的命令,可以这样做:

import psutil
pid = 1234 # The pid whose info you're looking for
p = psutil.Process(pid)
print(p.cmdline())

最后一行会打印出类似 ['/usr/bin/python', 'main.py'] 的内容。

还有一种更稳妥的方法来获取这些信息,这样可以确保如果这个进程已经不在运行了,也不会出问题:

import psutil
pid = 1234 # The pid whose info you're looking for
if pid in psutil.get_pid_list():
    p = psutil.Process(pid)
    print(p.cmdline())
10

使用 /proc 文件有一个缺点,就是它的可移植性比较差,这可能会影响到你的使用。下面是如何使用标准的命令行工具来解决这个问题。

ps -w -w -p <YOUR PID> -o cmd h

注意这里有两个 -w 选项,它们的作用是告诉 ps 命令不要截断输出(默认情况下它会这样做)。

在 Python 中读取这个输出非常简单,只需要调用一个函数 subprocess.check_output(),具体的用法可以在 这里 找到。

撰写回答