我有一个启动 3 个终端模拟器窗口的脚本:
#!/bin/sh
terminator --role='terminator-left' 2>/dev/null &
sleep 0.1
terminator --role='terminator-center' 2>/dev/null &
sleep 0.1
terminator --role='terminator-right' 2>/dev/null &
(我使用 --role 选项,以便我可以自动将窗口放置在不同的显示器上,在我的 openbox 配置文件中定义)
我在不同的虚拟桌面上多次启动此脚本。
如何在某种“进程组”中启动这 3 个终端,以便在其中任何一个进程终止时可以杀死所有剩余进程?
重要提示:我不想终止可能在脚本的不同实例中启动的所有终端(我不能只使用 pkill 或 pgrep 来终止与模式匹配的任何进程)
换句话说,假设我在虚拟桌面 1 和虚拟桌面 2 上启动脚本。
我现在在 2 个不同的虚拟桌面上有 3 个终端窗口。
当我退出虚拟桌面 1 上的一个终端时,我希望其余 2 个窗口自动终止,但不会影响在虚拟桌面 2 上运行的其他 3 个窗口的独立实例。
我所描述的可能吗?
我怎样才能做到这一点?
免责声明:
我没有机会在 openbox 下测试我的建议。我仅在 kde-plasma 下验证了它,
我的解决方案依赖于 POSIX 程序员手册中记录的
wait
shell 内部命令。使用 -n 选项,某些特定的实现可以使脚本更简单。该脚本基于以下想法:
注 1(重置处理程序):正如 aviro 在注释中正确观察到的那样,信号处理程序必须将 SIGCHLD 的处理重置为默认值,因为杀死剩余进程将触发其他(最多 2 个)SIGCHLD。
如果不这样做,将迫使 shell 处于某种递归情况(处理程序必须处理它自己生成的信号),根据 shell 实现或多或少地进行优雅的管理。(从无害的警告到超过某些最大递归深度或等效错误。)
注 2(保持 SIGCHLD 默认处理直到等待):正如 Martin Vegter 在注释中正确观察到的,该
trap ownkill CHLD
指令应紧接在等待指令之前放置。将其作为脚本的第一条指令(正如我在前面的版本中荒谬地建议的那样)将在第一个
sleep
进程终止后立即触发专用处理程序。使用 bash,您可以简单地收集所有进程 id,并在最后等待,以便当任何进程退出(bash 的
wait -n
)时,所有 id 都会被一些合适的信号杀死:由于其中一个 pid 已经失效,我们将
kill
stderr 重定向到 null 以避免出现错误消息。您可能愿意使用 systemd 瞬态单元,因为它的启动、控制和停止都很简单。假设您的 shell 脚本是,在其末尾
./myscript
添加一个命令,以便它不会立即完成,那么您可以使用以下命令启动它:wait -n
此命令立即返回消息
Running as unit: mytest1.service
,您可以使用常用命令查看创建的瞬态单元中正在运行哪些进程:您可以使用一个命令停止所有进程:
要多次运行同一脚本,只需确保
--unit=
每次使用不同的名称即可。如果它们都以 开头test
,那么您可以检查它们全部,或者通过将它们引用为 来停止它们test*
。请参阅man systemd-run了解可能有用的各种选项,例如
--setenv=
、--working-directory=
、--collect
、--wait
。请注意,您还可以在命令末尾将参数传递给脚本systemd-run
。