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

获取在Python子进程的终端内执行的命令的进程ID,python,subprocess,Python,Subprocess,我在Python子流程中的gnome终端中运行vim: >>> import subprocess >>> cmd=['gnome-terminal', '--', 'vim'] >>> p = subprocess.Popen(cmd) 可以使用p.pid获取gnome终端的进程ID,但是如何从Python脚本中获取vim的进程ID呢 尽管Bash中的pstree将vim显示为gnome终端的子进程,但psutils并没有列出它 >

我在Python子流程中的gnome终端中运行vim:

>>> import subprocess
>>> cmd=['gnome-terminal', '--', 'vim']
>>> p = subprocess.Popen(cmd)
可以使用
p.pid
获取gnome终端的进程ID,但是如何从Python脚本中获取vim的进程ID呢

尽管Bash中的
pstree
将vim显示为gnome终端的子进程,但psutils并没有列出它

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

这种行为是由gnome终端引起的

如果在shell中键入命令
ps | grep
,您将看到类似于
pts/0 00:00:00 gnome terminal

一个进程不起作用意味着它已经完成了它的任务并等待被杀死(或者行为不端,这里不是这样)。 这意味着您从python启动的进程已经完成了它的工作,并且正在等待python杀死它

现在,如果您查看
pstree
,您将看到另一个gnome终端进程已在根级别生成。这意味着您在Python中启动的gnome终端进程只是在根级别启动“真正的终端进程”并退出。 如果您使用
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
root 5047 0.0.0 pts/0 Z 10:07 0:00[gnome终端]
根5053 0.0 0.3 595276 30468?Sl 10:07 0:00/usr/lib/gnome终端/gnome终端服务器
根7147 0.0 0.0 12780 972分/0秒+10:17 0:00格雷普gnome终端
这是您现在已经失效的进程,还有一个新的
gnome终端服务器
进程<代码>gnome终端服务器是您正在寻找的流程


长话短说
pgrep-f gnome终端服务器
将返回您想要的pid。

我认为这很好

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秒。
这里我们创建了两个进程来获取vim编辑器的ID,我们使用stdout和stdin将进程
a
的输出提供给
b


然后我们使用
.communicate()
将进程
b
的stdout导入
输出

现在我们的
输出是以字节的形式出现的,所以我们使用
.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终端分叉的
21093
是gnome终端的id,它是vim的ppid。

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

如果我们试图验证这些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。

评论是否可以改进。

这里有一个解决方法。通过符号链接命名VIM,并找到其PID:

import subprocess as sub,time,os,signal

N=5
vims= [ sub.Popen(f'ln -fs $(which vim) /dev/shm/vim{vn} && gnome-terminal -- /dev/shm/vim{vn} -c "s/$/Welcome to vim{vn}/"', shell=True) for vn in range(N) ]

time.sleep(1)

for vn in range(N):
    # Get the pids of vims. Vim pid is not equal to proc.pid!
    phelper= sub.Popen(f'ps -o pid= -C vim{vn}',shell=True, stdout=sub.PIPE, stderr=sub.PIPE) 
    try:
        out,err= phelper.communicate(timeout=1)
        vims[vn]= (vims[vn],int(out.decode(encoding="utf8")))  # proc_object --> (proc_object,vim pid)
    except TimeoutExpired:
        pass
    phelper.kill()

# do something:
time.sleep(10)

for proc,vimpid in vims:
    os.kill(vimpid,signal.SIGTERM)

这里是我自己的Python only take,到目前为止运行良好。这个代码有什么问题吗

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)

但这仍然不是
vim
进程的PID。gnome终端服务器的子进程是gnome终端中运行的所有其他进程。我需要识别在由我的代码创建的子流程中运行的特定流程。运行
pstree-hp-s
将显示您想要的流程。如果我正在运行多个vim会话,这不会识别我正在寻找的vim流程。在我的代码中,只有一个vim流程是由subprocess命令启动的。我只想要这一个vim进程的pid,而不是任何其他可能处于活动状态的vim进程。@lecodesportif肯定是的,输出按
pid
的升序排序,如果希望代码启动最新的
vim
,它将是
output
的最后三个参数。这是因为pid是按升序分配的。您的最后一个参数是``而倒数第二个参数是
grep vim
,因此我们需要倒数第三个参数,即
output[len(output)-3]
,这给出了您的代码打开的最新vim。@lecodesportif在那里我更新了答案,找到了由您的代码启动的最新vim的pid。这听起来像是一个错误。您打算如何处理此信息;你最终希望实现什么?
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)