获取Python子进程中在终端内部执行的命令的进程ID

时间:2019-04-27 12:43:15

标签: python subprocess

我在Python子进程的gnome-terminal内部运行vim:

>>> import subprocess
>>> cmd=['gnome-terminal', '--', 'vim']
>>> p = subprocess.Popen(cmd)

可以使用p.pid获取gnome-terminal的进程ID,但是如何从Python脚本中获取vim的进程ID?

尽管Bash中的pstree将vim显示为gnome-terminal的子进程,但psutils并未列出它。

>>> import psutil
>>> terminal_process = psutil.Process(p.pid)
>>> terminal_process.children()
[]

4 个答案:

答案 0 :(得分:1)

此行为是由gnome-terminal引起的。

如果在外壳中键入命令ps | grep <pid>,则会看到类似于<pid> pts/0 00:00:00 gnome-terminal <defunct>的内容。

已终止的进程意味着它已完成任务并等待被杀死(或者行为异常,在这里不是这种情况)。 这意味着您从python启动的进程已完成工作,正在等待python杀死它。

现在,如果您查看pstree,您将看到在根级别已经生成了另一个gnome-terminal进程。这意味着您在Python中启动的gnome-terminal进程只是在根级别启动了“真正的终端进程”,然后退出了。 如果您进一步调查并使用ps aux | grep gnome-terminal查找以gnome-terminal开头的进程,您将看到类似以下输出:

root      5047  0.0  0.0      0     0 pts/0    Z    10:07   0:00 [gnome-terminal] <defunct>
root      5053  0.0  0.3 595276 30468 ?        Sl   10:07   0:00 /usr/lib/gnome-terminal/gnome-terminal-server
root      7147  0.0  0.0  12780   972 pts/0    S+   10:17   0:00 grep gnome-terminal

现在有一个已失效的过程,还有一个新的gnome-terminal-server过程。 gnome-terminal-server是您要寻找的过程。

长话短说pgrep -f gnome-terminal-server将返回您想要的pid。

答案 1 :(得分:1)

我认为这很好

import time
import subprocess

cmd=['gnome-terminal','--', 'vim']
p = subprocess.Popen(cmd)
time.sleep(10)

a = subprocess.Popen(['ps', '-eo', 'pid,ppid,command'], stdout = subprocess.PIPE)
b = subprocess.Popen(['grep', 'vim'], stdin = a.stdout, stdout = subprocess.PIPE)

output, error  = b.communicate()
output = output.decode("utf-8").split('\n')
print(output)

我使用time.sleep(10)的原因是由于某种原因vim的分叉速度没有那么快,所以我将其延迟了10秒钟。
在这里,我们创建2个用于获取vim编辑器ID的进程,并使用stdout和stdin将进程a的输出提供给b

然后,我们使用.communicate()将进程b的stdout放入output
现在我们的output是字节形式的,因此我们使用.decode("utf-8")将其解码为UTF-8,然后在每一行上拆分。
它产生输出:

rahul@RNA-HP:~$ python3 so.py
# _g_io_module_get_default: Found default implementation gvfs (GDaemonVfs) for ‘gio-vfs’
# _g_io_module_get_default: Found default implementation dconf (DConfSettingsBackend) for ‘gsettings-backend’
# watch_fast: "/org/gnome/terminal/legacy/" (establishing: 0, active: 0)
# unwatch_fast: "/org/gnome/terminal/legacy/" (active: 0, establishing: 1)
# watch_established: "/org/gnome/terminal/legacy/" (establishing: 0)
['21325 21093 vim', '21330 21318 grep vim', '']
rahul@RNA-HP:~$ 

要验证这一点:

rahul@RNA-HP:~$ ps aux | grep gnome-terminal
rahul    21093  1.7  2.4 978172 45096 ?        Ssl  19:55   0:02 /usr/lib/gnome-terminal/gnome-terminal-server
rahul    21374  0.0  0.0   8988   840 pts/0    S+   19:57   0:00 grep --color=auto gnome-terminal
rahul@RNA-HP:~$ ps -eo pid,ppid,command | grep vim
21325 21093 vim
21376 21104 grep --color=auto vim
rahul@RNA-HP:~$ 

在这里我们可以看到vim是从gnome-terminal 21093分叉的,它是gnome-terminal的ID,它是vim的ppid。

现在,如果我不使用time.sleep(10)

,就会发生这种情况
rahul@RNA-HP:~$ python3 so.py
['21407 21406 /usr/bin/python3 /usr/bin/gnome-terminal -- vim', '21409 21406 grep vim', '']

如果我们尝试验证这些PID是否存在:

rahul@RNA-HP:~$ kill 21407
bash: kill: (21407) - No such process
rahul@RNA-HP:~$ 

由于某些原因,这些ID不存在。
如果有多个vim实例: 它产生:

 ['21416 21093 vim', '21736 21093 vim', '21738 21728 grep vim', '']


获取最新的实例化vim的pid:

output = output[len(output) - 3]

我们的输出以pid的升序排序,我们的倒数第二个值是grep vim,因此我们需要倒数第三个参数来获取vim的pid。
评论是否可以改进。

答案 2 :(得分:0)

这是一种解决方法。通过符号链接命名vims,并找到其pid:

@OneToMany

答案 3 :(得分:0)

这是我自己的Python唯一选项,到目前为止效果很好。这段代码有任何问题吗?

import psutil, subprocess

cmd=['gnome-terminal', '--', 'vim']
editor_cmd=cmd[-1]  # vim

proc = subprocess.Popen(cmd)       
proc.wait()

# find the latest editor process in the list of all running processes
editor_processes = []
for p in psutil.process_iter():
    try:
        process_name = p.name()
        if editor_cmd in process_name:
            editor_processes.append((process_name, p.pid))
    except:
        pass
editor_proc = psutil.Process(editor_processes[-1][1])

print(editor_proc)