82

I want to write a shell script which will attach to a named tmux session, select a window (or pane) in that session and run a command in that selected window (or pane).

How do I do this from a bash script?

I know

tmux new-window -n:mywindow 'exec something'

allows me to send commands to a freshly created window, but I need something like

tmux select-window -t:0 'my command'

I suppose I could use send-keys but seems like there should be something that takes a command or list of commands that get run.

3 Answers 3

119

Each tmux pane is an interface for a single pty (pseudo tty). Non-split windows have a single pane; split windows have multiple panes.

tmux does not supply a way to add extra processes to a pane once it has been started with its initial command. It is up to that initial command’s process (usually a shell) to supply job control1 for that terminal.

If you want to clobber whatever is currently running in the pane, you can use respawn-pane -k to kill the existing command and replace it with a new one (e.g., respawn-pane -t sessionname:0.4 -k 'some -new command').

But, if you want to maintain whatever is currently running in the pane, then there may be no better option that simply “typing at it” with send-keys.

You might script it like this (attach last, because otherwise the script will just wait for you to detach before continuing):

session=whatever
window=${session}:0
pane=${window}.4
tmux send-keys -t "$pane" C-z 'some -new command' Enter
tmux select-pane -t "$pane"
tmux select-window -t "$window"
tmux attach-session -t "$session"

Note that, on the send-keys command, you should actually type the letters E n t e r, to tell tmux to send a newline key to the window.  (Naturally, every command ends with the Enter key.)


1Job control is the arbitration between multiple process groups of a single session that uses the tty as its controlling terminal. I.e., the Ctrl+Z suspend key, and the jobs, fg, and bg shell commands.

2
  • 4
    Thanks for this! I put #{session_name}:#{window_index}.#{pane_index} in my status line so I can quickly see which pane to send commands to. May 24, 2017 at 23:32
  • That's nice to prevent the window to be removed when the command returns.
    – Alexis
    Jan 22, 2022 at 11:14
22

You can use C-m instead of Enter. It's the same thing. Also, tmux makes it easy to send to the right / left pane by using -t right or -t left. And if you want to address a pane in another window, just prefix it with the window number and period, like -t 0.right.

Now you can write a simple Bash function to get the sequence of keys as argument and send it over to the target pane easily.

1
  • You can also use select-pane -t {last} for the last (previous) active pane.
    – bloody
    Apr 18, 2023 at 20:36
1

Add commands to a simple text file queue:

This is only a last resort, if you really wanted to run the command after the last one without killing it.

Example

  1. Write a bash script that takes a [cli command] and a [tmux pane name] as variables
  2. The script adds the command to a queue file which it titles to pertain to that pane only
  3. However the queue file's first line is merely a 0 or 1
  4. The script loops through simple attempt at changing the 0 to a 1 via a tmux send-keys command to the corresponding tmux pane. (If there is a command presently running in the pane, the send-keys command naturally does nothing. Otherwise, it changes the 0 to a 1.)
  5. In the same loop, the script then attempts to detect a 1 in the queue file.
  6. When the script detects that the 0 is a 1, it runs the next command in the queue, and deletes it from the file. It changes the 1 back to a 0.

To store commands, you could also use an "associative array"

The script stops looping when the array is empty.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .