我是 Linux 新手。我在不同的文件中有 python 脚本,每个脚本都执行所需的功能。
foo1.py
foo2.py
foo3.py
这些脚本中的每一个都应该在终止之前进行清理。此外,我想在终端中执行它们中的每一个,以分别交互和读取输出。
我已经实现了清理函数来捕获不同的终止信号(例如,SIGTERM、SIGINT 等)。
为了在终端中运行每个脚本,我使用为每个startup.sh
脚本打开一个xterm
终端,如下所示。
启动文件
xterm -e python foo1.py & pid1=$!
xterm -e python foo2.py & pid2=$!
xterm -e python foo3.py & pid3=$!
然后,按照我的逻辑,脚本foo3.py
是最重要的,因此如果它完成,其他两个也需要关闭。
wait $pid3
kill -15 $pid1
kill -15 $pid2
问题是 和$pid1
是$pid2
xterm 的 pid,而不是脚本 ( foo.py
) 本身的 pid。因此,当我终止 xterms ( kill -15 $pid
) 时,python 脚本没有机会执行其清理例程。
我试图捕获 xterm 发送到其子进程的信号(https://unix.stackexchange.com/a/54994/357513)但 python 脚本立即完成。
那么,有没有办法获得PID来自 xterm 内运行的脚本?或者是否有另一种方法来确保执行此类清理例程?
答案1
您的 python 脚本还应该捕获SIGHUP
它并干净退出。当 xterm 正在拆除它们运行的伪终端时,它们会得到一个SIGHUP
。无论如何,您都必须处理这个问题SIGHUP
,因为它们运行的终端可能会由于其他原因而消失,而不是xterm
被明确杀死(例如,X11 服务器本身终止)。
EIO
当尝试读取或写入没有主终端的从属终端时,您的脚本还应该正确处理错误。
无论如何,你可以通过以下方式杀死你的 python 脚本
pkill -P $pid1
(“被父级杀死”;参见联机帮助页的pkill
/ pgrep
)
并非所有 shell 都会将脚本的最后一个命令从 fork / exec / wait 优化为简单的 exec (例如dash
,/bin/sh
debian 等),因此,如果您必须运行复杂的 shell 命令,您最好exec
显式调用,如xterm -e 'script=$(...); exec python "$script"'
.
笔记:
WINDOWID
不完全回答这个问题,但查找从终端仿真器启动的进程的一种不可靠但有效的方法是搜索在其环境中设置的进程:
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