简体   繁体   English

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

[英]Get process ID of command executed inside terminal in Python subprocess

I run vim inside gnome-terminal in a Python subprocess:我在 Python 子进程中的 gnome-terminal 内运行 vim:

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

It is possible to get the process ID for gnome-terminal with p.pid , but how can I get the process ID for vim from within the Python script?可以使用p.pid获取 gnome-terminal 的进程 ID,但是如何从 Python 脚本中获取 vim 的进程 ID?

Even though pstree in Bash shows vim as a child process of gnome-terminal, psutils does not list it.尽管 Bash 中的pstree vim 显示为 gnome-terminal 的子进程,但 psutils 并未列出它。

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

This behavior is caused by gnome-terminal.此行为是由 gnome-terminal 引起的。

If you type the command ps | grep <pid>如果您键入命令ps | grep <pid> ps | grep <pid> inside your shell, you will see something similar to <pid> pts/0 00:00:00 gnome-terminal <defunct> . ps | grep <pid>在你的 shell 中,你会看到类似于<pid> pts/0 00:00:00 gnome-terminal <defunct>

A process being defunct means it has finished its task and is waiting to get killed (or is misbehaving which isn't the case here).一个进程被取消意味着它已经完成了它的任务并正在等待被杀死(或者行为不端,这里不是这种情况)。 This means the process you launched from python has completed its job and is waiting for python to kill it.这意味着你从 python 启动的进程已经完成了它的工作,正在等待 python 杀死它。

Now if you look at pstree , you will see that another gnome-terminal process has been spawn at the root level.现在,如果您查看pstree ,您将看到另一个 gnome-terminal 进程已在根级别生成。 This means that the gnome-terminal process you launched in Python simply launched the "real terminal process" at the root level and exited.这意味着您在 Python 中启动的 gnome-terminal 进程只是在根级别启动了“真正的终端进程”并退出。 If you further investigate and look for processes starting with gnome-terminal using ps aux | grep gnome-terminal如果您进一步调查并使用ps aux | grep gnome-terminal查找以 gnome-terminal 开头的进程ps aux | grep gnome-terminal , you will see output like : ps aux | grep 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

There is your now defunct process, and a new gnome-terminal-server process.有你现在已经不复存在的进程,以及一个新的gnome-terminal-server进程。 gnome-terminal-server is the process you are looking for. gnome-terminal-server是您正在寻找的进程。

Long story short pgrep -f gnome-terminal-server will return the pid you want.长话短说pgrep -f gnome-terminal-server将返回您想要的 pid。

I think this works fine我认为这很好用

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)

The reason I used time.sleep(10) is because for some reason vim was not getting forked that fast so, I delayed it for 10 seconds.我使用time.sleep(10)原因是由于某种原因vim没有被分叉那么快,所以我延迟了 10 秒。
Here we create 2 process for getting the ID of vim editor, we give the output of process a to b using stdout and stdin.这里我们创建了 2 个获取 vim 编辑器 ID 的进程,我们使用 stdout 和 stdin 将进程a的输出ab

Then we use .communicate() to get stdout of process b into output .然后我们使用.communicate()将进程b stdout 输出到output
Now our output is in form of bytes so we decode it to UTF-8 using .decode("utf-8") and then split on every new line.现在我们的output是字节的形式,所以我们使用.decode("utf-8")将其解码为 UTF-8,然后在每个新行上拆分。
It produces the output:它产生输出:

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:~$ 

To verify this:要验证这一点:

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:~$ 

Here we can see that vim is forked from gnome-terminal 21093 is the id of gnome-terminal which is the ppid of vim.在这里我们可以看到 vim 是从 gnome-terminal 分叉出来的21093是 gnome-terminal 的 id,它是 vim 的 ppid。

Now, this happened if I didn't use time.sleep(10)现在,如果我不使用time.sleep(10)发生这种情况

rahul@RNA-HP:~$ python3 so.py
['21407 21406 /usr/bin/python3 /usr/bin/gnome-terminal -- vim', '21409 21406 grep vim', '']

If we try to verify if those PID exist:如果我们尝试验证这些 PID 是否存在:

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

Those ID dont exist for some reason.由于某种原因,这些 ID 不存在。
If there are multiple instances of vim: It produces:如果有多个 vim 实例:它会产生:

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


To get the latest instantiated vim's pid:要获取最新实例化的 vim pid:

output = output[len(output) - 3]

Our output is sorted in ascending order of pid's and our last and second last values are我们的输出按 pid 的升序排序,我们的最后一个和倒数第二个值是and grep vim so we need the third last argument for getting the pid of vim.grep vim所以我们需要最后第三个参数来获取 vim 的 pid。
Comment if something can be improved.评论是否可以改进。

Here is a workaround.这是一个解决方法。 Name the vims by symbolic links, and find their pids:通过符号链接命名 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)

Here is my own Python only take, which works well so far.这是我自己的 Python 唯一版本,到目前为止效果很好。 Any issues with this code?这段代码有什么问题吗?

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM