I am a big fan of tmux – a terminal multiplexer. Think of it as a text version of vnc client, with many more powerful features. In this post I will demo some of the tmux techniques that I use quite often.
1) GNU version of tmux
2) Default shell is BASH
For demo’s purpose I make up a dummytask.sh to simulate the task(s) that we will be running in tmux windows:
#!/bin/bash taskname=$@ ans='' if [ -n "$taskname" ]; then while [ ! "$ans" == "q" -a ! "$ans" == "Q" ]; do read -e -n 1 -p "Running task $taskname, to exit, press q(Q). " ans done echo "Done task $taskname." else echo "Usage: $0 task." echo "Example1: $0 debugging" echo "Example2: $0 importing data" fi
Example: create a tmux session with session name mysess
tmux new-session -s mysess -d
If the option -d (detached) is omitted, you will be taken directly to the first window titled “0:bash” once the command is executed and any commands afterwards will be entered into that window. Therefore it’s a good habit to use option -d whenever creating a new session.
Example: create a new tmux session and change the first default window title to task1
[ type q, Enter, exit, Enter if the sess tmux session is currently attached ]
In the first example, tmux will create a first window titled “0:bash” (could be ksh, csh etc depending on default shell setting) by default, to change to something else, simply using -n (name) option:
tmux new-session -s sess -d -n task1
Example: create tmux session mysess if it has not been created yet
tmux list-session 2>&1 | grep -q "^mysess:" || tmux new-session -s sess -d
Notes: 2>&1 is to suppress error output “failed to connect to server: Connection refused”, which occurs when there are no tmux sessions running. -q is used to suppress the normal output of of grep. It won’t affect the result but using it makes the commands less distracting. Regular expression ^sess: is used to make sure it won’t match session name such as “sessionabc” by mistake. Logical operator || is just a shorthand form of if [ ! condititon ]; then … fi.
Example: create a new window title mywin in an existing tmux session mysess, if the window has not existed yet, create the session first if it hasn’t existed yet
#!/bin/bash sess=mysess wn=mywin tmux list-session 2>&1 | grep -q "^$sess" || tmux new-session -s $sess -d tmux list-window -t $sess 2>&1 | grep -q ": $wn \[" || tmux new-window -t $sess -n $wn
Example: run a script in mysess:mywin in the above example
#!/bin/bash sess=mysess wn=mywin tmux list-session 2>&1 | grep -q "^$sess" || tmux new-session -s $sess -d tmux list-window -t $sess 2>&1 | grep -q ": $wn \[" || tmux new-window -t $sess -n $wn tmux send-keys -t $sess:$wn "./dummytask.sh cooking" Enter
How do we know the above script is doing what we intended to do? Check out the next example.
Example: attach tmux session mysess
tmux a -t mysess
Example: run a script in the first window of the newly created tmux session
tmux new-session -s mysess -n mywin "bash dummytask.sh cooking"
This works but there’s a problem, once you exit the program by pressing q or Q, tmux session also terminates. This gets more annoying when a program crashes and you don’t get any debug info, a better handling of the task will be provided in the following example.
Example: run program in a tmux window and exit to bash shell inside the window if the program exits or crashes
#!/bin/bash sess=mysess wn=mywin # duplicate session or window handling code here # ... tmux send-keys -t $sess:$wn "./dummytask.sh cooking" Enter
Example: how to check if a tmux session is attached
Sometimes it’s desired to run certain command not in a tmux window, use the following code to detect if attempt is made to run some command inside a tmux window:
if [ "$TERM" = "screen" -a -n "$TMUX" ]; then echo "This command should be run when tmux is not attached" fi
Example: attach a tmux session with a specific window selected
#!/bin/bash sess=mysess tmux list-session 2>&1 | grep -q "^$sess" || tmux new-session -s $sess -d wn=win0 tmux list-window -t $sess 2>&1 | grep -q ": $wn \[" || tmux new-window -t $sess -n $wn tmux send-keys -t $sess:$wn "./dummytask.sh task 0" Enter wn=winX tmux list-window -t $sess 2>&1 | grep -q ": $wn \[" || tmux new-window -t $sess -n $wn tmux send-keys -t $sess:$wn "./dummytask.sh important mission" Enter wn=win1 tmux list-window -t $sess 2>&1 | grep -q ": $wn \[" || tmux new-window -t $sess -n $wn tmux send-keys -t $sess:$wn "./dummytask.sh another thing" Enter # here's the meat of this script, select window winX before attaching the session tmux select-window -t $sess:winX && tmux a -t $sess
In tmux sometimes we might need to attach a session with the specific window selected so that we can start working without additional switching window steps. I just found one of the ways to accomplish this is:
tmux select-window -t sess:win && tmux attach -t sess
Credit goes to http://tofu.org/drupal/node/183 [ lines 78 & 79 ]
Here’s how I got stuck:
1) Remote access to a linux serverA
2) Launch tmux, Ctrl-b c to create a new window
3) From the new window, remote access to serverB, then run tmux att under shell to attach an existing tmux session (on serverB)
4) Now if I use the shortcut key Ctrl-b d, I can only detach from the session on serverA, because the tmux session on server B also uses Ctrl-b as the prefix
a) Press Ctrl-b n until the window containing the ssh session to server B becomes the current window
b) Press Ctrl-b :
c) Enter tmux command set -g prefix C-a
d) Press Ctrl-b d, tmux session on serverB is now detached, type exit to close the new window created in step 2, this step is optional though as the “nested” tmux session is detached from the ssh shell
e) Press Ctrl-a :
f) Enter tmux command set -g prefix C-b
Step c changes prefix to Ctrl-a so it won’t conflict with the tmux shortcut prefix from serverB. Step f changes the prefix back to Ctrl-b for serverA.