2

I'm new to Linux. I have python scripts in different files, each one performing a desired function.

foo1.py 
foo2.py 
foo3.py

Each one of these scripts should do cleanup before being terminated. Moreover, I would like to execute each one of them in a terminal to interact and read the outputs separately.

I already implemented the cleanup function to catch different kill signals (e.g., SIGTERM, SIGINT, etc.).

To run each one of the scripts in a terminal, I am using a startup.sh that opens one xterm terminal for each, just like below.

startup.sh

xterm -e python foo1.py & pid1=$! 
xterm -e python foo2.py &  pid2=$!
xterm -e python foo3.py &  pid3=$!

Then, in my logic, the script foo3.py is the most important, so if it finishes, the other two need to close as well.

wait $pid3
kill -15 $pid1
kill -15 $pid2

The problem is that $pid1 and $pid2 are pids for the xterms and not for the scripts (foo.py) themselves. So, when I kill the xterms (kill -15 $pid), the python scripts have no chance to execute their cleanup routine.

I tried to catch the signal sent by xterm to its child process (https://unix.stackexchange.com/a/54994/357513) but the python scripts are immediately finished.

So, Is there a way to get the pids from the scripts running inside xterm? Or Is there another way to make sure that such cleanup routines will be executed?

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255

1 Answers1

2

Your python scripts should also catch SIGHUP and do a clean exit on it. They will get a SIGHUP when xterm is tearing down the pseudoterminal they run in. You will have to handle the SIGHUP anyway, because the terminal they run in may disappear because of other causes than xterm being explicitly killed (eg. the X11 server itself terminating).

Your scripts should also correctly handle EIO errors when trying to read or write to a slave terminal with no master.

Anyways, you could kill your python scripts by just

pkill -P $pid1

("kill by parent"; see the manpage of pkill / pgrep)

Not all shells optimize the last command of a script from a fork / exec / wait into a simple exec (example dash, the /bin/sh on debian and alike), so if you have to run a complex shell command you better call exec explicitly, as in xterm -e 'script=$(...); exec python "$script"'.

Note:

Not exactly replying this question, but an unreliable but effective way to find the processes started from a terminal emulator is to search the processes which have its WINDOWID set in their environment:

pids_by_env(){ grep -aslP "\b($1)\0" /proc/[0-9]*/environ | grep -oP '\d+'; }

pids_by_window(){ pids_by_env "WINDOWID=$(printf '%d' "$(xwininfo "$@" | awk '/id:/{print$4}')")"; }

$ ps $(pids_by_window)
[click!]
  PID TTY      STAT   TIME COMMAND
11244 pts/8    Ss     0:00 bash
11297 pts/8    S+     0:00 vu [censored].pdf
  • more info about how xterm runs commands and when and how xterm is sending SIGHUP. –  Jun 12 '19 at 14:06
  • @mosvy thank you sir. Sorry for the codes "typos". I just adapted this from a previous version where i was using more than one bash command per xterm and was creating a list with pid variables. I'm also trying to catch SIGHUP, but without success. I'll try to handle the EIO erros and see what happens. Also, will check the proposed idea to see if it will work correctly. – Wilson Borba Neto Jun 12 '19 at 14:07
  • 4
    Thanks for the edit, @mosvy, that will indeed kill the python (as well as any other children of the xterm) but can you think of a way of getting the actual PID of the python when running like this? I am not at all sure it's even possible. – terdon Jun 12 '19 at 14:10