Backbeat Software
Photo by Andrew Schultz on Unsplash

Level up with tmux

Tips to improve your terminal skills with tmux, the terminal multiplexer.

Glynn Forrest
Wednesday, September 30, 2020

Following on from the last development productivity post, let’s look at using tmux to speed up working with terminals in development.

tmux is a terminal multiplexer, allowing you to tile multiple terminals side by side in a single terminal window. This can be useful in development, when you need to run multiple long running processes at the same time, e.g. development servers, file watchers, and docker containers.

For example, here’s my tmux session for BackupsHQ:

There are two windows called “editor” and “server”. In the “editor” window I have three panes - one for my editor and two for shells in different directories. In the “server” window I have four panes with long running processes - a web server, docker containers, webpack, etc.

The tmux wiki explains the difference between sessions, windows, and panes in depth.

Tmux is a little hard to get comfortable with, so here are some tips I’ve learned to level up your tmux skills.

Use a sensible prefix key

Every tmux command begins with a prefix key, e.g. Prefix + c to create a new window or Prefix + x to close the current pane.

The prefix is Ctrl-b out of the box, which isn’t particularly friendly.

Instead, I recommend Ctrl-a - your left hand can reach it easily while your right hand hits the other shortcut key. Here are the relevant lines to add to .tmux.conf:

# Remove the default prefix key binding
unbind C-b

# Set the prefix key to ctrl-a
set -g prefix C-a

# Send the C-a key to the terminal by pressing it twice
bind C-a send-prefix

Also, if you set the Caps Lock key as another Ctrl (highly recommend for emacs users like me), hitting Ctrl-a is a very simple left hand chord - Caps Lock and a.

An earlier alternative to tmux, GNU Screen, uses Ctrl-a as its prefix too.

Vi keybindings

Moving between panes is done with the arrow keys, e.g. Prefix + ↓ to move to the pane below. For vi aficionados, key bindings can be easily added:

# Move between panes with vi keys
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

Capital letters can be used to resize panes:

# Resize the current pane with upper case vi keys
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

And Ctrl could even be used to move between windows:

# Move to the window left and right
bind -r C-h select-window -t :-
bind -r C-l select-window -t :+

Tmux also supports vi keybindings when in copy mode. Add setw -g mode-keys vi to your config, then entering copy mode (Prefix + [) will enable vi-style navigation of the current pane. Even visual mode (v) works!

Zoom

A novel tmux feature for users coming from Screen is the “zoom” command. Pressing Prefix + z will make the active pane fill the entire window, and pressing it again will revert to its previous position. I find this especially handy when inspecting failing tests - I put a test runner in a small pane underneath my editor, and zoom the pane when looking at the failing results.

As well as Prefix + z, use Prefix + ? to see all the available keys. There are lots of useful combinations!

Quick session switcher

Switching between sessions from within tmux is fairly easy (Prefix + s), but creating and attaching to sessions outside of tmux is a little trickier:

# Create a new tmux session called 'work' and attach to it
tmux new -s work

# Attach to an existing session called 'work'
tmux attach -t work

It gets more cumbersome if you’ve forgotten about an existing session:

# The 'work' session already exists
tmux new -s work
duplicate session: work

A bit of bash scripting and fzf, the fuzzy-finding swiss army knife, can solve this problem:

# Attach to or create a tmux session with fuzzy matching
tm() {
  # If we're in a tmux session, we want to call `switch-client`, otherwise we want `attach-session`.
  [[ -n "$TMUX" ]] && command="switch-client" || command="attach-session"
  # If an argument has been supplied, try to attach to that session.
  # If that doesn't work, create a new session with the argument as the name and attach to it.
  if [ $1 ]; then
    tmux $command -t "$1" 2>/dev/null || (tmux new-session -d -s $1 && tmux $command -t "$1"); return
  fi
  # If no argument has been supplied, list all tmux sessions and get the user to pick with fzf
  session=$(tmux list-sessions -F "#{session_name}" 2>/dev/null | fzf --select-1 --exit-0) &&  tmux $change -t "$session" || echo "No sessions found."
}

After adding this function in your .bashrc or .zshrc, attaching to sessions is easy:

# Attach to the 'work' session, creating it if it doesn't exist
tm work

# Attach to the existing 'work' session (short-hand supported)
tm wo

# List all sessions and pick the one to attach to with fzf
tm

Quick reload of the config file

When tweaking .tmux.conf, it can get frustrating to close the session and start it again to see the changes applied. With this line, Prefix + r will reload .tmux.conf without restarting tmux:

bind r source-file ~/.tmux.conf \; display "Reloaded .tmux.conf"

Watch out for config syntax differences

Depending on the version of tmux, the syntax of the configuration file can be very different.

For example, setting colours on recent tmux versions looks like this:

set -g status-style fg=default,bg=colour234
set -g message-style fg=default,bg=colour234
set -g pane-border-style fg=colour234,bg=default
set -g pane-active-border-style fg=colour67,bg=default
setw -g window-status-style fg=default,bg=colour234
setw -g window-status-current-style fg=colour67,bg=colour234
setw -g window-status-activity-style fg=colour234,bg=colour245

While on older versions, it looks like this:

set -g status-fg default
set -g status-bg colour234
set -g message-fg default
set -g message-bg colour234
set -g pane-border-fg colour234
set -g pane-border-bg default
set -g pane-active-border-fg colour67
set -g pane-active-border-bg default
setw -g window-status-fg default
setw -g window-status-bg colour234
setw -g window-status-current-fg colour67
setw -g window-status-current-bg colour234
setw -g window-status-activity-fg colour234
setw -g window-status-activity-bg colour245

More resources

More from the blog

The search for the perfect setup script cover image

The search for the perfect setup script

How to onboard your developers as smoothly as possible.


Glynn Forrest
Monday, August 31, 2020

First look at Symfony UX cover image

First look at Symfony UX

Our first impressions of the Symfony UX initiative.


Glynn Forrest
Friday, December 11, 2020

Webpack hot module replacement in server-rendered apps cover image

Webpack hot module replacement in server-rendered apps

Get the benefits of webpack-dev-server without building an SPA.


Glynn Forrest
Friday, July 31, 2020