Tmux scripting

Posted on Wednesday, January 21, 2015



 Now that I have the basics of tmux figured out and have put together a nice ~/.tmux.conf configuration file I want to move onto tmux scripting.

Here is my need.  I need tmux to open up create 8 panes and have each pane issue a command to tail a log, via ssh, to 8 different servers.

How can this be done?




If you don't have tmux installed I wrote up a guide at http://www.whiteboardcoder.com/2014/12/installing-tmux.html  that shows how to install it on Ubuntu (10.04, 12.04, and 14.04), OSX via brew, and even cygwin.




Create a session and have it run a single command


I can create a session, in a detached state, named tail_log by running this command.


     > tmux new -s tail_log -d


I can send this "named" session a command by using tmux send-keys.


     > tmux send-keys -t tail_log 'date' C-m


The C-m acts like a carriage return. 
If I then log into this session


     > tmux attach -t tail_log




I can see that the date command was run.

Can you run more than one command?



I tried this


     > tmux send-keys -t tail_log 'echo "one"' C-m 'echo "two"' C-m






And it worked just fine!







Creating a tmux session with 2 Horizontal panes and send each a command


I can run the following two commands to create a tmux session with 2 horizontal planes


     > tmux new -s tail_log -d
     > tmux split-window -v -t tail_log


Attaching to the session I see


     > tmux attach -t tail_log





How do I specify which pane to send the command to using the send-keys command?

Here is what I found. The section where you designate the session to send the command to "-t session" really has the format [session]:[window].[pane]

If I want to send a command to the first window, window 0, and the first pane, pane 0, I can execute the following command.



     > tmux send-keys -t tail_log:0.0 'echo "pane 0"' C-m
     > tmux send-keys -t tail_log:0.1 'echo "pane 0"' C-m


Results in






Creating a tmux session with 8 Evenly spaced horizontal planes


If I try to run the following commands


     > tmux new -s tail_log -d
     > tmux split-window -v -t tail_log
     > tmux split-window -v -t tail_log
     > tmux split-window -v -t tail_log
     > tmux split-window -v -t tail_log
     > tmux split-window -v -t tail_log
     > tmux split-window -v -t tail_log
     > tmux split-window -v -t tail_log



I get the following error after four splits



And If I attach to the session


     > tmux attach -t tail_log


I see






Each split is splitting the next split to it keeps getting ½'d in size.



If instead I ran the following commands


     > tmux new -s tail_log -d
     > tmux split-window -v -t tail_log:0.0
     > tmux split-window -v -t tail_log:0.0
     > tmux split-window -v -t tail_log:0.1
     > tmux split-window -v -t tail_log:0.0
     > tmux split-window -v -t tail_log:0.2
     > tmux split-window -v -t tail_log:0.1
     > tmux split-window -v -t tail_log:0.3


This works… kinda



The screen is split but the panes are out of order.  The ordering from top to bottom is 0, 4, 2, 5, 1, 6, 3, 7.  This ordering is not good. 
How do I fix it?

I found the answer: using the select-layout tool.

Here is the set of commands to run  to split it evenly into 8 sections.


     > tmux new -s tail_log -d
     > tmux split-window -v -t tail_log
     > tmux split-window -v -t tail_log
     > tmux split-window -v -t tail_log
     > tmux select-layout -t tail_log even-vertical
     > tmux split-window -v -t tail_log
     > tmux select-layout -t tail_log even-vertical
     > tmux split-window -v -t tail_log
     > tmux select-layout -t tail_log even-vertical
     > tmux split-window -v -t tail_log
     > tmux select-layout -t tail_log even-vertical
     > tmux split-window -v -t tail_log
     > tmux select-layout -t tail_log even-vertical





And they are in the correct order!



You can quickly change the layout to even-horizontal by running


     > tmux select-layout -t tail_log even-horizontal






You can quickly change the layout to tiled by running


     > tmux select-layout -t tail_log tiled













Putting it all together in a script


Create a script


     > touch tmux-tail-logs.sh
     > chmod u+x tmux-tail-logs.sh
     > vi tmux-tail-logs.sh


Here is the script


tmux new -s tail_log -d


#Create 8 horizontal panes
tmux split-window -v -t tail_log
tmux split-window -v -t tail_log
tmux split-window -v -t tail_log
tmux select-layout -t tail_log even-vertical
tmux split-window -v -t tail_log
tmux select-layout -t tail_log even-vertical
tmux split-window -v -t tail_log
tmux select-layout -t tail_log even-vertical
tmux split-window -v -t tail_log
tmux select-layout -t tail_log even-vertical
tmux split-window -v -t tail_log
tmux select-layout -t tail_log even-vertical

#Tail logs
tmux send-keys -t tail_log:0.0 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
tmux send-keys -t tail_log:0.1 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m
tmux send-keys -t tail_log:0.2 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
tmux send-keys -t tail_log:0.3 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m
tmux send-keys -t tail_log:0.4 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
tmux send-keys -t tail_log:0.5 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m
tmux send-keys -t tail_log:0.6 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
tmux send-keys -t tail_log:0.7 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m

#attach to tmux tail_log window
tmux attach -t tail_log




Then run the script


     > ./tmux-tail-logs.sh





It worked!

Now to kill all the panes first detach from the screen Ctrl+a then d.   (I changed my prefix from Ctrl+b to Ctrl+a



Then run


     >  tmux kill-session -t tail_log


Trying to tail 8 log files this way does not really work well, 8 is just too much.

I am going to reduce it to 4 and try that out.

Here is the updated script


tmux new -s tail_log -d


#Create 8 horizontal panes
tmux split-window -v -t tail_log
tmux split-window -v -t tail_log
tmux split-window -v -t tail_log
tmux select-layout -t tail_log even-vertical

#Tail logs
tmux send-keys -t tail_log:0.0 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
tmux send-keys -t tail_log:0.1 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m
tmux send-keys -t tail_log:0.2 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
tmux send-keys -t tail_log:0.3 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m

#attach to tmux tail_log window
tmux attach -t tail_log



Run this script


     > ./tmux-tail-logs.sh





Four rolling logs seems more manageable.





Another option using bind-key in the .tmux.conf file


There is another option, you can add commands to the .tmux.conf file.

Edit the ~/.tmux.conf file


     > vi ~/.tmux.conf


And add the following to the end of this file


# Create new window with 4 panes that tail logs
bind-key M-l new-window -n tail_logs \; \
        split-window -v -t 1 \; \
        split-window -v -t 1 \; \
        split-window -v -t 1 \; \
        send-keys 'tmux select-layout even-vertical' C-m \; \
        select-pane -t 0 \; \
        send-keys 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m \; \
        select-pane -t 1 \; \
        send-keys 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m \; \
        select-pane -t 2 \; \
        send-keys 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m \; \
        select-pane -t 3 \; \
        send-keys 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m \; \

# Close a window named tail_logs




One way to reload the changes is to start or reattach to a tmux session and press Ctrl+b then ":" then type the following command


  source-file ~/.tmux.conf




To run use this press Ctrl+a then alt+l .

This will create a new window with four panes, evenly space them and tail 4 logs.

To kill this window press Ctrl+a then alt+k to kill the tail_logs window.






Another option use the source-file command


You can load custom configuration files from within tmux!
Here is a short example.

Create a file called ~/.tmux.log.conf


     > vi ~/.tmux.log.conf


And place the following into it.



#====================================
#
# This tmux Configuration file does the following
# Creates 4 panes on the screen and starts tailing
# a different log on each pane
#
# To run this
#    * Start tmux and run the following command in tmux
#    * tmux source-file .tmux.log.conf
#
#
#====================================

split-window -v
split-window -v
split-window -v

select-layout even-vertical


select-pane -t 0
send-keys 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
select-pane -t 1
send-keys 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m
select-pane -t 2
send-keys 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
select-pane -t 3
send-keys 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m





Then start up tmux


     > tmux


Then from within tmux run the following command to load the configuration file


     > tmux source-file ~/.tmux.log.conf








The screen is split into four panes and each pane is now tailing a log!


Here is my final script.  I updated it with a kill key.  Ctrl+a then k (I changed my prefix to Ctrl+a from Ctrl+b)



#====================================
#
# This tmux Configuration file does the following
# Creates 4 panes on the screen and starts tailing
# a different log on each pane
#
# To run this
#    * Start tmux and run the following command in tmux
#    * tmux source-file .tmux.log.conf
#
#
#====================================

split-window -v
split-window -v
split-window -v

select-layout even-vertical


select-pane -t 0
send-keys 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
select-pane -t 1
send-keys 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m
select-pane -t 2
send-keys 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
select-pane -t 3
send-keys 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m

bind-key k select-pane -t 0 \;  \
     send-keys 'C-c' \; \
     select-pane -t 1 \; \
     send-keys 'C-c' \; \
     select-pane -t 2 \; \
     send-keys 'C-c' \; \
     select-pane -t 3 \; \
     send-keys 'C-c' \; \
     kill-window \;


Each pane is sent Ctrl+c to cancel the tail command, then the tmux window itself is killed.


Yet another script


If you prefer your panes to be in a tile format



Use this script.


#====================================
#
# This tmux Configuration file does the following
# Creates 4 panes on the screen and starts tailing
# a different log on each pane
#
# To run this
#    * Start tmux and run the following command in tmux
#    * tmux source-file .tmux.log.conf
#
#
#====================================

split-window -v
split-window -v
split-window -v

select-layout tile


select-pane -t 0
send-keys 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
select-pane -t 1
send-keys 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m
select-pane -t 2
send-keys 'ssh 192.168.0.150 tail -f /var/log/sensu/sensu-client.log' C-m
select-pane -t 3
send-keys 'ssh 192.168.0.152 tail -f /var/log/sensu/sensu-client.log' C-m

bind-key k select-pane -t 0 \;  \
     send-keys 'C-c' \; \
     select-pane -t 1 \; \
     send-keys 'C-c' \; \
     select-pane -t 2 \; \
     send-keys 'C-c' \; \
     select-pane -t 3 \; \
     send-keys 'C-c' \; \
     kill-window \;




Hope this helps someone out there.


References
[1]        tmux: Productive Mouse-Free Development
            Author: Brian P. Hogan
                Accessed 1/2015










This post is a part of and epic, the Tmux epic.


Epic Goal:   Learn how to use tmux to open 8 panes that each start to tail a different serverlog via ssh, all via a script.


1 comment:

  1. Your link to ~/.tmux.conf is broken. It's missing the "h" at the start of "http"

    ReplyDelete