2

I run vim inside gnome-terminal in a Python subprocess:

>>> 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?

Even though pstree in Bash shows vim as a child process of gnome-terminal, psutils does not list it.

>>> import psutil >>> terminal_process = psutil.Process(p.pid) >>> terminal_process.children() [] 
1
  • This sounds like an XY problem. What do you intend to do with this information; what are you actually eventually hoping to accomplish? Commented Apr 27, 2019 at 14:37

4 Answers 4

1

This behavior is caused by gnome-terminal.

If you type the command ps | grep <pid> inside your shell, you will see something similar to <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.

Now if you look at pstree, you will see that another gnome-terminal process has been spawn at the root level. This means that the gnome-terminal process you launched in Python simply launched the "real terminal process" at the root level and exited. If you further investigate and look for processes starting with gnome-terminal using ps aux | grep gnome-terminal, you will see output like :

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 is the process you are looking for.

Long story short pgrep -f gnome-terminal-server will return the pid you want.

Sign up to request clarification or add additional context in comments.

3 Comments

But that still isn't the PID of the vim process.
The child processes of gnome-terminal-server are all other processes running in the gnome-terminal. I need to identify the specific process that is running in the subprocess created by my code.
running pstree -hp -s <pid> will display the process you want.
1

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.
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.

Then we use .communicate() to get stdout of process b into 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.
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.

Now, this happened if I didn't use 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:

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

Those ID dont exist for some reason.
If there are multiple instances of vim: It produces:

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


To get the latest instantiated vim's pid:

output = output[len(output) - 3] 

Our output is sorted in ascending order of pid's and our last and second last values are and grep vim so we need the third last argument for getting the pid of vim.
Comment if something can be improved.

4 Comments

This doesn't identify the vim process I am looking for if I'm running multiple vim sessions.
There is exactly one vim process which is launched by the subprocess command in my code. I only want the pid of that one vim process, not any other vim processes that might be active.
@lecodesportif Yes surely, the output is sorted in ascending order of pid, if you want the lastest vim launched by your code it would be the third last argument of output. This is because pid's are assigned in ascending order. Your last argument will be ` ` and second last will be grep vim so we need the third last ie. output[len(output) - 3], this gives latest vim opened by your code.
@lecodesportif there I updated the answer to find pid of latest vim launched by your code.
0

Here is my own Python only take, which works well so far. 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) 

Comments

0

Here is a workaround. Name the vims by symbolic links, and find their 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) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.