Suppose that app X is running in the foreground in tmux pane. I'd like to send a given signal, e.g. SIGUSR1, to app X. Can I configure a tmux keybinding to send a signal to the currently-selected pane's foreground process (or process group)?
2 Answers
In my Kubuntu ps
can give me the ID of the foreground process group on the terminal that the process is connected to. The keyword is tpgid
. If I tell ps
to query the process identified by tmux
as #{pane_pid}
then I will get the foreground process group ID in this pane.
The following binding (in ~/.tmux.conf
) will make prefixk send SIGUSR1 to the foreground process group (the default prefix is Ctrl+b):
bind-key k run-shell 'kill -s USR1 -- "-$(ps -o tpgid:1= -p #{pane_pid})"'
Notes:
The dash (
-
) before$(…)
is responsible for targeting the foreground process group. You can try without the dash to target one process only; it will be the foreground process group "leader". There is no guarantee the "leader" (still) exists though. Targeting the group is a sane approach, it's similar to Ctrl+c sending SIGINT to the group, although the mechanism is different.:1
is taken from this answer: Formatps
command output without whitespace. Getting rid of leading spaces is crucial when we prepend the dash.There's a race condition:
kill
acts afterps
and there is no guarantee the process group is still in the foreground (or exists at all).You may be unfortunate and hit prefixk around the time the process you want to target exits. This way you may inadvertently send SIGUSR1 to another process. It may be the shell. And then…
The default action for SIGUSR1 is to terminate. In particular your interactive shell being in the foreground (i.e. awaiting command) may exit upon prefixk. Bash does. You can prevent this by setting up a trap beforehand:
trap '' USR1
will make the shell ignore the signal. In this case child processes will also ignore the signal, unless they explicitly choose to handle it (e.g.dd
does this).trap : USR1
will make the shell "ignore" the signal (react by doing nothing), but this will not affect the behavior of child processes.

- 21,864
Tmux provides the pane_pid
, but that's going to be the PID of the topmost process in the pane, which is usually going to be the shell. You'll need to dig a bit deeper to find the PID of the foreground process, but you can use pane_pid
as the starting point.
Simple version -- Something like:
bind k run-shell "kill -s SIGUSR1 $(cat /proc/#{pane_pid}/task/#{pane_pid}/children)"
I believe that should work if there are no background processes in the pane.
If you may have multiple sibling processes running in the shell, with some of them backgrounded, then it gets a bit more complicated. I believe you'll need to do something like use ps -h --ppid #{pane_pid} -O stat
to get the child processes for the pane_pid
, then determine which one of them is running in the foreground (i.e. has a +
in the STAT
column), and parse out that PID.
One possible implementation:
bind k run-shell "kill -s SIGUSR1 $(ps -h --ppid #{pane_pid} -O stat | grep -o '^[[:blank:]]*[[:digit:]]\\+[[:blank:]]\\+[^[:blank:]]*+' | cut -d ' ' -f2)"
That will, however, still fail if there is no child process (i.e. the foreground process in the pane is the shell itself).
If you need to take it to the next level of robustness, of course, move it to a shell script and check if there actually are child processes before sending the signal.

- 3,547
:1
is not compatible with theps
implementation onmacos
, so I have adoptedsed
to strip away leading whitespace:bind-key k run-shell 'kill -s USR1 -- "-$(ps -o tpgid= -p #{pane_pid} | sed "s/^[[:blank:]]*//")"'
– Jasha Jan 17 '22 at 02:11