![发送信号到 tmux 窗格中的进程](https://linux22.com/image/201075/%E5%8F%91%E9%80%81%E4%BF%A1%E5%8F%B7%E5%88%B0%20tmux%20%E7%AA%97%E6%A0%BC%E4%B8%AD%E7%9A%84%E8%BF%9B%E7%A8%8B.png)
假设应用程序 X 在 tmux 窗格的前台运行。我想向应用程序 X 发送给定信号,例如 SIGUSR1。我可以配置 tmux 键绑定以向当前选定窗格的前台进程(或进程组)发送信号吗?
答案1
在我的 Kubuntu 中,ps
可以给我进程所连接的终端上的前台进程组的 ID。关键字是tpgid
.如果我告诉查询由asps
标识的进程,那么我将在此窗格中获取前台进程组 ID。tmux
#{pane_pid}
以下绑定(在 中~/.tmux.conf
)会将prefixkSIGUSR1 发送到前台进程组(默认prefix为Ctrl+ b):
bind-key k run-shell 'kill -s USR1 -- "-$(ps -o tpgid:1= -p #{pane_pid})"'
笔记:
前面的破折号(
-
)$(…)
负责定位前台进程团体。您可以尝试不使用破折号,仅针对一个进程;它将成为前台进程组的“领导者”。但不能保证“领导者”(仍然)存在。以组为目标是一种明智的方法,它类似于Ctrl+c向组发送 SIGINT,尽管机制不同。:1
摘自这个答案:设置ps
命令输出的格式,不含空格。当我们在前面添加破折号时,摆脱前导空格至关重要。有一个竞争条件:
kill
在之后执行ps
,并且不能保证进程组仍然在前台(或根本存在)。您可能会不幸地prefixk在您想要定位的进程退出时遇到问题。这样您可能会无意中将 SIGUSR1 发送到另一个进程。可能是外壳。进而…
SIGUSR1 的默认操作是终止。特别是,处于前台的交互式 shell(即等待命令)可能会在prefixk.巴什确实如此。您可以通过预先设置陷阱来防止这种情况:
trap '' USR1
将使 shell 忽略该信号。在这种情况下,子进程也将忽略该信号,除非它们明确选择处理它(例如dd
这样做)。trap : USR1
将使 shell“忽略”该信号(通过不执行任何操作来做出反应),但这不会影响子进程的行为。
答案2
Tmux 提供了pane_pid
,但这将是窗格中最顶层进程的 PID,该进程通常是 shell。您需要深入挖掘才能找到前台进程的 PID,但您可以将其用作pane_pid
起点。
简单版本——类似:
bind k run-shell "kill -s SIGUSR1 $(cat /proc/#{pane_pid}/task/#{pane_pid}/children)"
我相信如果窗格中没有后台进程,这应该可行。
如果您可能有多个同级进程在 shell 中运行,其中一些进程处于后台,那么情况会变得更加复杂。我相信您需要执行类似 use 的ps -h --ppid #{pane_pid} -O stat
操作来获取 的子进程pane_pid
,然后确定其中哪一个在前台运行(即列+
中有STAT
),并解析出该 PID。
一种可能的实现:
bind k run-shell "kill -s SIGUSR1 $(ps -h --ppid #{pane_pid} -O stat | grep -o '^[[:blank:]]*[[:digit:]]\\+[[:blank:]]\\+[^[:blank:]]*+' | cut -d ' ' -f2)"
然而,如果有的话,这仍然会失败不子进程(即窗格中的前台进程是 shell 本身)。
当然,如果您需要将其稳健性提升到一个新的水平,请将其移至 shell 脚本并检查是否确实存在是发送信号之前的子进程。