How to set pane titles with tmuxinator - tmux

How do you set a unique title on each pane in a tmuxinator session?
I'm trying to run multiple panes to show the output from htop being run through ssh to different servers. My configuration looks like:
project_name: Server Monitor
windows:
- servers:
layout: tiled
panes:
- ssh -t -i mykey.pem user#server1 htop
- ssh -t -i mykey.pem user#server2 htop
- ssh -t -i mykey.pem user#server3 htop
When I launch this with tmuxinator local, it runs the commands just fine and I see the output from htop. However, the panes all look the same and the SSH title isn't shown, making it nearly impossible to tell which pane corresponds to which server.
How do I change my configuration so that a unique title is shown on each pane?
This example shows that this feature is supported in the underlying tmux, but I'm not sure how to access this through tmuxinator.

What you need to do is first enable pane status in your .tmux.conf with the lines:
set -g pane-border-format "#{pane_index} #{pane_title}"
set -g pane-border-status bottom
Then add to your tmuxinator config a printf command that will send the appropriate escape sequence to dynamically set the pane title. You will have 2 commands now per pane, so you need to add another level of indentation with a name.
project_name: Server Monitor
windows:
- servers:
layout: tiled
panes:
- p1:
- printf '\033]2;%s\033\\' 'server1'
- ssh -t -i mykey.pem user#server1 htop
- p2:
- printf '\033]2;%s\033\\' 'server2'
- ssh -t -i mykey.pem user#server2 htop
- p3:
- printf '\033]2;%s\033\\' 'server3'
- ssh -t -i mykey.pem user#server3 htop
You need at least tmux 2.3 to have pane titles shown in the borders.

For anyone else who comes across this and:
Doesn't want to change their layout
Has a problem parsing the structure in Meuh's answer (I was getting a undefined method shellescape for #<Array error.
You still need to add these to your .tmux.conf:
set -g pane-border-format "#{pane_index} #{pane_title}"
set -g pane-border-status bottom
You can just add a ; before the ssh command and do this:
name: myBoxes
root: ~/
windows:
- hosts:
layout: tiled
panes:
- printf '\033]2;%s\033\\' 'role_storage_v45 : hostname2.net'; ssh 10.20.30.1
- printf '\033]2;%s\033\\' 'role_dns_v15 : hostname1.net'; ssh 10.20.30.2

Related

How to send-keys to remote ssh tmux session running inside a local tmux session?

From my local tmux session I start multiple remote tmux sessions with ssh.
Each remote machine occupied one window locally.
Unfortunately each one of these windows is considered one pane even if the remote tmux session has multiple panes.
For example. If I have this setup locally:
Window 1: general window not ssh-ed into anywhere.
Window 2: is an ssh into a remote tmux session that has 6 panes in first window and a second window.
If from window 1 locally I do:
tmux send-keys -t 2.6 "ls" C-m;
the "ls" wont get executed in window 2 pane 6, but it will be in window 2 in whatever pane is selected at the time.
Is there a way to specify which pane the command goes to on the remote session?
For reference I have this setup in my tmux that gets referenced locally and remotely:
bind -T root F12 \
set prefix None \;\
set key-table off \;\
set status-style "fg=colour245,bg=colour238" \;\
if -F '#{pane_in_mode}' 'send-keys -X cancel' \;\
refresh-client -S \;\
bind -T off F12 \
set -u prefix \;\
set -u key-table \;\
set -u status-style \;\
refresh-client -S

Change background color of tmux pane depending on remote hostname

If I ssh into a remote server from tmux in a single pane, is it possible to change the background color of the pane based on the server name?
Let's say all my prod servers start with prod_XYZ and a dev server starts with dev_XYZ. If I ssh into these two servers, can I color them differently based on the type of server I am on? That is, based on the server prefix?
I know tmux panes now understand color. So if I can detect the ssh command is being used then I can figure the name of the server and send the command select-pane -t:.1 -P 'fg=blue,bg=red' to tmux. But how do I (A) send the color to the correct pane; (B) get the server name from the terminal to color tmux?
The easiest way is to write a script or shell function and then alias it to ssh, something like (not tested):
#!/bin/sh
if [ -n "$TMUX" ]; then
case "$1" in
prod_*)
tmux selectp -P bg=red
;;
esac
fi
ssh "$#"
tmux selectp -P default

Getting command running in a tmux pane

Is there a way to show the command which is currently running at a tmux pane?
I tried 'history', but it does not seem to show the commands which I had executed at tmux.
I also tried 'ps -ef', but it does not show the full command in the case like "./a.sh ; ./b.sh"
I found several answers online that include ps ... | tail -1. Unfortunately, these don't always work because sometimes the order of the commands is swapped, e.g. for two separate panes I get:
$ ps -t /dev/pts/12 -o args=
-bash
mpv some_movie.mp4
$ ps -t /dev/pts/10 -o args=
micro some_file.txt
-bash
I really wanted a single line of output so that I could show it in the status bar, but what I ultimately ended up going with is ps --forest via run-shell. It seems to always reliably show the correct order and with more information should there be nested commands running (e.g. via a bash script). Its output looks like:
$ ps --forest -o args -g $$
COMMAND
-bash
\_ ps --forest -o args -g 1695
Solution
So in my .tmux.conf, I've got:
bind '`' run-shell 'ps --forest -o pid,args -g #{pane_pid}'
It will replace the contents of your pane with the output from the ps --forest command. Once you type esc or ^C, the ps output disappears, and your pane goes back to whatever it was doing :) Ends up looking like:
running script.sh, which calls other-script.sh, which sleeps for 30s
viewing pane process tree via keybinding
(Old question but for future reference)
Try: tmux list-panes -t <your_pane_name> -F '#{pane_current_command}'
https://man7.org/linux/man-pages/man1/tmux.1.html#FORMATS
Try setting pane-border-status to bottom or top in your configuration file, with the tmux command prompt or just running tmux set pane-border-status bottom. Borders should appear around the panes and info about the current process appears much like in a regular terminal window's title bar.
I suspect the command wasn't written to the history file as the shell with the stuck/long-running job wasn't done yet.
You might try pstree -U to see process in their parent/child tree.

multiple panes with tmuxinator

I' trying to build a tmuxinator with multiple windows and in one of them i`d like to build 2 panes:
name: bigbang-server
root: ~/projects/bigbang
windows:
- CORE:
- ...
- CONSOLE:
- ...
- FUND_TRANSACTIONS:
- ...
- CLIENT_POSITIONS:
pre_window: cd ~/projects/bigbang_services/
panes:
server:
- env PORT=3002 rails server
sidekiq:
- bundle exec sidekiq -C config/sidekiq.yml
it doesnt run any of my last window commands, here its debug:
# Window "CLIENT_POSITIONS"
tmux select-window -t 1
tmux select-pane -t 0
if [ -z "$TMUX" ]; then
tmux -u attach-session -t bigbang-server
else
tmux -u switch-client -t bigbang-server
fi
It seems there are some points to fix.
pre_window: should be top-level, not under windows:.
Any hash element (like name:) is not allowed under the pane:.
Like this.
name: bigbang-server
root: ~/projects/bigbang
pre_window: cd ~/projects/bigbang_services/
windows:
- CORE:
- ...
- CONSOLE:
- ...
- FUND_TRANSACTIONS:
- ...
- CLIENT_POSITIONS:
panes:
- env PORT=3002 rails server
- bundle exec sidekiq -C config/sidekiq.yml
The way you wrote the commands for the panes in that particular window is wrong.
It should have been something like this:
windows:
- CLIENT_POSTIONS:
panes:
- cd ~/projects/bigbang_services/
- env PORT=3002 rails server
- bundle exec sidekiq -C config/sidekiq.yml
This creates 2 horizontal splits first then splits the first one vertically.
To use horizontal or vertical splits throughout the window,
use main-horizontal or main-vertical.
Like this:
windows:
- CLIENT_POSTIONS:
layout: main-vertical # or main-horizontal
panes:
- cd ~/projects/bigbang_services/
- env PORT=3002 rails server
- bundle exec sidekiq -C config/sidekiq.yml

How to send a command to all panes in tmux?

I like to call :clear-history on panes with a huge scrollback. However, I want to script a way to send this command to all the panes in the various windows.
I know how to send a command to all the windows, courtesy of this question, but how do I send a command to all the panes of which window as well?
send-keys and synchronize-panes from the tmux manpage come to mind, but I'm not sure how to marry them together. But maybe there is a simpler way to do this.
Extra Observations:
Thinking about this a little bit, tmux list-panes -a seems to list all the panes in the current session. Pretty useful to start off with. Where do I go from here?
Have you tried following in tmux window with multiple panes
Ctrl-B :
setw synchronize-panes on
clear history
A bit late to the party but I didn't want to set and unset synchronize-panes just to send one command so I created a wrapper function around tmux and added a custom function called send-keys-all-panes.
_tmux_send_keys_all_panes_ () {
for _pane in $(tmux list-panes -F '#P'); do
tmux send-keys -t ${_pane} "$#"
done
}
I also create a wrapper around the tmux command to simplify calling this function (for convenience). The wrapper and the above code are all here.
This allows me to run tmux send-keys-all-panes <command> or tmux skap <command to send <command> to all panes.
Note that tmux is aliased to my wrapper function tmux_pp.
Update June 2019
Quick illustration on how to configure your own binding for synchronize panes.
Added the following into my tmux.conf (the comments certainly apply to my overall configuration):
# synchronize all panes in a window
# don't use control S, too easily confused
# with navigation key sequences in tmux (show sessions)
unbind C-S
bind C-Y set-window-option synchronize-panes
Now, I can toggle the ability to synchronize commands across multiple panes with <C-a><C-y>.
(Yes, I remapped the bind key to Ctrl a).
my tmux version is 1.9a, and this works for me, one key is enough for both on and off
bind-key X set-window-option synchronize-panes\; display-message "synchronize-panes is now #{?pane_synchronized,on,off}"
None of the above answers worked for me (tmux v2.3), but this did, from the bash command line:
for _pane in $(tmux list-panes -a -F '#{pane_id}'); do \
tmux clear-history -t ${_pane} ; done
A more generalized script, for tmux commands other than 'clear-history' would just replace that element with a parameter, eg. $1. Do be careful if you intend to write a script to handle a series of tmux commands, as "-t ${_pane}" will need to be applied to each.
Note that the -a parameter to tmux list-panes is required to cover all panes in all windows in all sessions. Without that, only panes in your current tmux window will be affected. If you have more than one tmux session open and only want to apply the command to panes within the current session, replace -a with -s (It's all in the tmux man page).
I haven't the mod points to comment directly on each of the above answers, so here's why they weren't working for me:
The problem that I had with #shailesh-garg 's answer was that the sync affected only commands issued within the panes, not tmux commands issued using Ctrl-B : which are outside the panes.
The three problems that I had with #kshenoy 's answer were that:
it sends keystrokes to within a pane, not to the tmux operation
of that pane, so for instance, if one had a bash shell running in
the pane and one used the script to send "clear-history", those
would be the keystrokes that would appear in the bash command-line.
A work-around would be to send "tmux clear-history" or to pre-pend
"tmux " to "$#", but I haven't edited the answer because of my other
problems with the answer;
I couldn't figure out how to send a
new-line character without literally breaking the line;
Even when I did that, sending "tmux clear-history" had no effect.
If you want to send your command to every pane in every window in every session, add this to your .bashrc:
send_command_to_every_pane() {
for session in `tmux list-sessions -F '#S'`; do
for window in `tmux list-windows -t $session -F '#P' | sort`; do
for pane in `tmux list-panes -t $session:$window -F '#P' | sort`; do
tmux send-keys -t "$session:$window.$pane" "$*" C-m
done
done
done
}
You can then use it like this:
send_command_to_every_pane source ~/.bash_profile
Change "$*" to "$#" if you want that behavior, but in my experience this is what you want.
tmux send-keys -t <session id> <command> C-m
Replace the "session id" and "command" accordingly.
This is my utility function to do it, only executing the command when there there is nothing running in the pane.
#!/bin/bash
_send_bash_command_to_session() {
if [[ $# -eq 0 || "$1" = "--help" ]] ; then
echo 'Usage: _send_bash_command_to_session $session_name what ever command you want: '
return
fi
input_session="$1"
input_command="${#:2}"
for _pane in $(tmux list-panes -s -t ${input_session} -F '#{window_index}.#{pane_index}'); do
# only apply the command in bash or zsh panes.
_current_command=$(tmux display-message -p -t ${input_session}:${_pane} '#{pane_current_command}')
if [ ${_current_command} = zsh ] || [ ${_current_command} = bash ] ; then
tmux send-keys -t ${_pane} "${input_command}" Enter
fi
done
}
tmux_set_venv() {
_current_session=$(tmux display-message -p '#{session_name}')
_send_bash_command_to_session ${_current_session} workon $1
}
Example targeting a session called dev, enabling a python virtualenv in all panes that are in bash or zsh, avoiding executing the command in panes with vim or any other executable:
_send_bash_command_to_session dev workon myvirtualenv
or easier to remember: to do it in the current session:
tmux_set_venv myvirtualenv
Find my configuration file with this function.
You can combine synchronize-panes and send-keys in a single shortcut to send commands to all the panes:
Predefined tmux command clear-history:
bind-key C set-option -w synchronize-panes on\; clear-history \; set-option -w synchronize-panes off
Prompt an arbitrary tmux command:
bind-key p command-prompt -p "Panes command: " "set-option -w synchronize-panes on; %% ; set-option -w -u synchronize-panes"
Prompt an arbitrary shell command:
bind-key p command-prompt -p "Panes command: " "set-option -w synchronize-panes on; send-keys %%\\n ; set-option -w -u synchronize-panes"
By default, byobu uses tmux as backend. It's a wrapper that make things much easier:
Shift+F9:
Ctrl+F9:
Shift+F1
Admittedly only semi-related, I found I could make the status background red when I toggle synchronize-panes so it's obvious when I switch back to a window with an unknown synchronize-panes state:
bind-key C-x setw synchronize-panes on \; set-window-option status-bg red \; display-message "pane sync on"
bind-key M-x setw synchronize-panes off \; set-window-option status-bg default \; display-message "pane sync off"

Resources