Получить идентификатор процесса команды, выполненной внутри терминала в подпроцессе Python - PullRequest
2 голосов
/ 27 апреля 2019

Я запускаю vim внутри gnome-терминала в подпроцессе Python:

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

Можно получить идентификатор процесса для gnome-терминала с помощью p.pid, но как я могу получить идентификатор процесса для vim из скрипта Python?

Несмотря на то, что pstree в Bash показывает vim как дочерний процесс терминала gnome, psutils не перечисляет его.

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

Ответы [ 4 ]

1 голос
/ 27 апреля 2019

Я думаю, что это прекрасно работает

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, мы даем вывод процесса a в b, используя stdout и stdin.

Затем мы используем .communicate(), чтобы получить стандартный выводобработайте b в output.
Теперь наш output находится в форме байтов, поэтому мы декодируем его в UTF-8, используя .decode("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-терминал, который является ppid для vim.

Теперь это произошло, если я не использовал 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:~$ 

Эти идентификаторы по какой-то причине не существуют.
Если существует несколько экземпляров vim: он производит:

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


Чтобы получить последний pid экземпляра vim:

output = output[len(output) - 3]

Наш вывод сортируется в порядке возрастаниязначения pid, а также наше последнее и второе последнее значения и grep vim, поэтому нам нужен третий последний аргумент для получения pid для vim.
Прокомментируйте, если что-то можно улучшить.

1 голос
/ 27 апреля 2019

Такое поведение вызвано gnome-терминал.

Если вы введете команду ps | grep <pid> внутри вашей оболочки, вы увидите нечто похожее на <pid> pts/0 00:00:00 gnome-terminal <defunct>.

Процесс, являющийся несуществующим, означает, что он завершил свою задачу и ждет, пока его убьют (или ведет себя не так, как здесь). Это означает, что процесс, запущенный вами из python, завершил свою работу и ждет, пока python его уничтожит.

Теперь, если вы посмотрите на pstree, вы увидите, что на корневом уровне был создан другой процесс терминала gnome. Это означает, что процесс gnome-Terminal, который вы запустили в Python, просто запустил «настоящий процесс терминала» на корневом уровне и завершил работу. Если вы продолжите исследовать и искать процессы, начинающиеся с gnome-терминала, используя 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

Это ваш ныне несуществующий процесс и новый gnome-terminal-server процесс. gnome-terminal-server - это процесс, который вы ищете.

Короче говоря pgrep -f gnome-terminal-server вернет желаемый pid.

0 голосов
/ 28 апреля 2019

Вот мой собственный дубль 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)
0 голосов
/ 28 апреля 2019

Вот обходной путь. Назовите vims символическими ссылками и найдите их pids:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...