Try Tmux for easy navigation in the terminal

If you spend enough time on your daily work in the command line, I recommend you at least try Tmux. It is a terminal multiplexer, which means that it allows having several terminal sessions in the same OS window. It supports Unix-like systems, including macOS.

This works by splitting the window into panes which are small sub-windows. The user can then hide these panes in the background, organize or close them. The layouts can also be personalized.

Some apps already support a similar behavior. For example, in iTerm2 or Terminator, you can create tabs for different shell sessions. You can also split those panes and even resize them with the mouse. This is not so different than Tmux but it has some limitations.

If you are connecting to a remote server via SSH, you would need to create a new connection every time that you open a new tab. However, you could run Tmux in the server only once and create as many panes or windows as you would like without exiting it.

The differences are not that big between these apps and Tmux, at least for the initial usage. But as I will comment later, Tmux has a great ecosystem and is quite powerful to programmatically organize its content and move around.

Tmux has a client-server architecture. There is always one server and there can be multiple clients. These communicate with each other via a Unix socket. It also contains sessions, windows, and panes. You can think of them in a hierarchical way: each session can have many windows and each window many panes.

Tmux also supports detaching from the existing client. This means that if you run the detach command, the session would still be running, and you can close the terminal window and open it later. Because Tmux is still running in the background, you can attach into the Tmux client again.

When I first used it, there were a few things that put me off. One was the status bar, which many users keep, but I wanted to remove. The reason to remove is that I wanted to keep the terminal window as clean as possible, as it is where I do most of my work, including the text editor.

Was glad to find that it is highly customizable. By creating a .tmux.config file in the home directory, it is possible to change many of the default parts of the UI. For example, for hiding the status bar you can add: set -g status off.

In addition, due to my terminal color theme, I decided to update some of the colors displayed on other parts of the UI. These are examples of how to change some colors:

set -wg mode-style bg=white,fg=blue
set -wg message-style bg=white,fg=blue

This setup is more pleasing when using a light theme.

Normally, all shortcuts for Tmux are triggered by first pressing a prefix key. By default, it is Control + b. A few examples of common commands are:

  • Splitting the window in two vertical panesl with Control + b, %
  • Moving from the left pane to the right one with Control + b, →
  • Entering scroll mode with Control + b, [

You can also configure custom key bindings. For example, I have the following bindings in my configuration:

bind c new-window -c "#{pane_current_path}"
bind '"' split-window -c "#{pane_current_path}"
bind % split-window -h -c "#{pane_current_path}"

These lines override some of the existing keybindings to create the new windows or panes using the same current directory. For the first of the three lines, it means that the combination: Control + b and then c will run the new-window command.

You can also run commands manually, by pressing the prefix key followed by : (colon). This behavior may seem familiar if you use the vi text editor before. From Tmux command bar, you have autocomplete by clicking tab.

The commands can accept a string for the command to run in the new window or pane. When passing a custom command, the windows are short-lived and are closed as soon as the command finished.

The commands run from the command bar (Control + b, :) can also be run directly from the command line passing them to the tmux command. You can try running the following:

tmux split-window "echo Some temporal command; sleep 5"

That command assumes that you already have Tmux running. It is also possible to start the Tmux server passing some commands, e.g. creating sessions. This is quite useful, I have different script files to start Tmux with different sessions and windows opened. For example:

tmux \
    new-session -s abc \; \
    send-keys 'cd ~/development/abc; clear' C-m \; \
  \
    new-session -s def \; \
    send-keys 'cd ~/development/def; sh ./some_script.sh' C-m \; \
  \
    kill-session -t 0  \; \
    select-window -t 0 \;

In this case, it is starting Tmux and creating two sessions: abc and def. In each of them it is using cd to change the current directory, and then in one of them is running a script. Finally, it removes the default sessions created when starting Tmux, which is the target 0.

One of the drawbacks of removing the status bar is that it is more difficult to know which is the current session and window. One way to know this is by pressing the prefix key plus w. Tmux will then display a tree view of the current sessions and windows. In that view it is easy to navigate and see the names of the sessions.

This approach is not the most practical as it would require to constantly press the shortcut. Another alternative is to modify your existing bash prompt to also show some information. I have the following Shell code in my .bashrc file to achieve it:

getTmuxNumber() {
  echo $(tmux display-message -p '#I')
}

# if $TMUX is empty means it is not a Tmux client
if [[ -z $TMUX ]]; then
  TMUX_PREFIX_A="" && TMUX_PREFIX_B="·"
else
  TMUX_PREFIX_A="\$(getTmuxNumber) " && TMUX_PREFIX_B=""
fi

Then I can use $TMUX_PREFIX_A and $TMUX_PREFIX_B when setting up the prompt along with other values, something like: export PS1="....$TMUX_PREFIX_A...$TMUX_PREFIX_B".

Another cool feature of Tmux is that it supports plugins. There is not a huge amount of them, but they are written in multiple languages, like Shell or Ruby. There is a plugin manager called TPM that makes it a bit easier. To use it you just need to follow the instructions in the GitHub repo.

These are the packages that I have enabled in my Tmux configuration, which I completely recommend:

There are more interesting plugins, and the GitHub organization has a specific repository for listing them, you can find it here.

With these plugins, one can organize several Tmux environments divided into sessions for each important project. This makes it fast to move around without the need to keep opening and closing terminal windows.

I found myself using it so much that decided to optimize one of the most frequent steps: switching between sessions. With sessionist plugin, it is trivial to create sessions and organize them by name.

This is a small script I wrote to leverage the other fantastic tool fzf. It allows changing sessions very quickly by choosing a session by name using fuzzy search.

  • ~/.tmux.conf
bind b split-window 'sh ~/choose_session.sh'
  • ~/change_session.sh
#!/usr/bin/env bash

SESSION=$(tmux ls | grep -o '^.*: ' | sed 's|: ||' | fzf --color light)

if [ -z "$SESSION" ]; then exit 0; fi

tmux switch-client -t "$SESSION"

If you want to know more about Tmux, I recommend that you install it locally and take a look at the extensive manual page: man tmux. You can also find it online here. There are other online resources like this compact cheatsheet.

You can also find many alternatives nowadays, and some will have support for Windows. Still for Linux, one of the classic ones is GNU Screen.

Back to the posts list
Loading ...