Atomic Object’s blog on everything we find fascinating.

As a "Professional Problem Solver," I design, implement, and maintain systems to host and deploy software applications. Additionally, I maintain Atomic's internal IT infrastructure and provide technical support to all employees.

Less Perplexing Terminal Multiplexing with tmux

Tmux has been getting a lot of attention lately. As George Nachman works toward a deeper integration of iTerm2 with tmux, more people are becoming aware of the ‘other’ terminal multiplexer. Around the office, people have been asking how I use tmux. While I’m also an avid iTerm2 user, I’m not sure if the new ‘deep integration’ will be worth the additional complexity. Tmux is useful enough on its own.

As a professional problem solver, I spend a considerable portion of my day working at a command prompt. Lately, I have been doing this work within a terminal multiplexer called tmux. Here are some tips for getting started.

Installing tmux

I use homebrew to manage packages on my machine. Installing tmux is as simple as:brew install tmux

Getting Started with tmux

Concepts

Before diving into the details of using tmux, it’s good to have a mental model of how some of the pieces fit together.

Tmux operates on a client/server model. A tmux server hosts any number of sessions. A session is a group of one or more windows. A window may contain one or more panes. Unlike screen, tmux considers windows and panes to be different types of entities. A pane may be broken out of a window into a new window, and a window’s pane may be joined to another window, but windows and panes are distinct.

Multiple clients can connect to the same server and access either the same or different sessions (and switch between them). Clients connect to the server via a socket. File permissions on the socket limit access to the tmux server. Read write access is needed for an interactive session. You can also have multiple servers running on different sockets if you need.

Let’s review with an example and get started. If you run tmux for the first time without any arguments it will start a new server, a new session containing one window that contains one pane in which your default-shell is running, AND a new client connected to that session on that server over a socket (probably somewhere in /tmp).

Phew.

If you detach this client from the server without explicitly closing the session, the session (and the server) will continue running (below we’ll see how this can become a problem if you’re not careful).

OK, Let’s get started.

Defaults

Tmux’s default ‘prefix’ is Ctrl + b (C-b). This works fine for me, and is a welcome change from screen’s default prefix of Ctrl + a which conflicts with the readline key mapping for jumping to the beginning of a line. (Side node: C-b also conflicts with an Emacs/readline mapping to move backwards one character. I’ve seen C-q suggested as a safer alternative prefix.)
If you’d rather use something else as a prefix, it’s easy to remap.

Adding the following to your ~/.tmux.conf will remap your prefix to C-a like screen:

unbind C-b
set -g prefix C-a
bind C-a send-prefix

Another default setting you may want to change is the starting window index. Starting with 0 is counterintuitive when it’s at the other end of the keyboard from where the window appears.
To reset the starting window index to 1 use:set -g base-index 1

Basic Keys

When getting started, the first things you’ll want to know are how to navigate and how get additional help. This should help get you started:

prefix ? — displays the majority of the current key bindings.prefix c — creates a new window in the current session.prefix 1 — selects window 1.prefix 2 — selects window 2, etc.prefix & — closes the current window after prompting.prefix " — splits the current pane horizontally in the current window.prefix % — splits the current pane vertically in the current window.prefix q — briefly display the ids of the panes in the current window.prefix o — select next pane (move focus to pane with next id).prefix x — closes the current pane after prompting.prefix : — open the tmux command-prompt (tab completion helps for remembering/discovering useful commands)

Customization

One of the best features of tmux is how easy it is to configure. Here are a few things that I’ve used to make my life easier.

If your terminal emulator supports xterm mouse reporting, tmux can also be configured to allow you to select windows, change pane focus, resize panes, and enter copy-mode (scroll-back buffer) using the mouse:

# Just click it
set-option -g mouse-select-pane on
set-option -g mouse-select-window on
set-option -g mouse-resize-pane on
# Scroll your way into copy mode (scrollback buffer)
# and select text for copying with the mouse
setw -g mode-mouse on

Send to All with syncronize-panes

Tmux has a command that will send your input to all panes simultaneously. This is handy when you want to run commands on multiple servers simultaneously.
I toggle this on and off with prefix a:bind-key a set-window-option synchronize-panes

How to Share Sessions

When confronted with particularly complex and consequential tasks (i.e. refactoring Puppet manifests), Justin and I mitigate risks with ad hoc pairing. Tmux helps us pair on these tough problems by allowing us to easily share our terminal sessions.

Unlike screen which uses setuid and custom ACLs to allow for multiple users1, tmux utilizes a client/server model with a socket. By specifying a named socket and ensuring the correct permissions, you can allow other users to connect. To make this easier, I have the following aliases defined:

Running tmuxmulti will either attach to an existing session or create a new one on the socket /tmp/multi. By ensuring that Justin’s account has read/write access to this socket, I allow him to join the same session. With tmuxer I ssh into Justin’s machine and attach to his tmux session. Generally I have iTerm2 open fullscreen with two vertically split panes. On the left is my workspace and on the right is Justin’s.

Gotchas

When running tmux on OS X, you may encounter a few annoying problems as a result of child processes becoming detached from their parent environments.

Fixing the Clipboard on OS X

If you use pbcopy and pbpaste to transfer text from your terminal sessions to the system clipboard, you may find that they do not work from within tmux (or screen or vim). A detailed explanation of why this is can be found here.

TL;DR? Thanks to the work of Paul Hinze you can easily fix it like this:brew install reattach-to-user-namespace --wrap-pbcopy-and-pbpaste

Losing Track of ssh-agent

It’s possible that you may also encounter an issue where new shells lose track of your ssh-agent. If you encounter this, the annoying result is that you are asked for your password each and every time you need to use your private key (you do have your private key password-protected, right?).

In order to fix this, you need to set an environment variable with the location of the socket that the agent is running on, either by inheriting it from a parent shell’s environment, or rediscovering it.

There are scripts, like this one that will attempt to find ssh-agent’s socket after it has been lost, but I recently discovered that tmux has an option that should save you the trouble. Just add: set -g update-environment -r to your .tmux.conf—it will automatically copy a handful of useful environment variables into new shells from the parent environment.

Color Issues

You may find that things are ugly that weren’t before; for example Vim with a carefully crafted color scheme like Solarized.
Odds are that your terminal type is not being reported correctly. Try adding set -g default-terminal "screen-256color" to your .tmux.conf and see if that helps.

Configuration Changes not Being Loaded

This is a big one that confuses a lot of people. Because tmux uses a client/server model, it only loads .tmux.conf when the server is started, not when a new client attaches. The server will continue running as long as you at least one session running. To manually reload your configuration, you can run :source-file ~/.tmux.conf from the tmux command-line.

Too Many Sessions

Be careful that you’re not creating a new session each time you launch tmux. It’s easy to pile up old and unused sessions without realizing it. Check what sessions are running on a tmux server by hitting prefix s while in a session or running tmux list-sessions from the command line. If you’re using a named socket you may first specify it like this: tmux -S /tmp/mytmuxsocket list-sessions.

Additional Resources

These blog posts (and countless others) provide some great information on getting started with tmux:

1 I had trouble getting screen’s multi-user mode to work on OS X Lion. There is a bug where screen refuses to allow new clients to attach with a message about having the wrong PID. This is actually what led me to start using tmux.

Yes, sorry for the confusion, I do mean Ctrl + b. I struggled for a while over which syntax to use for describing key combinations and eventually settled on the format that is used in the tmux manpage and configuration file.

I’m not sure if you’d be interested in it, but I’ve written a tmux script called wemux to make the various methods of multi-user sessions easier/more full featured.

It uses a host/client concept to allow hosts to create new sessions and only allow clients to mirror (connected in read only mode) or pair (connected in edit mode) to the host session.

It has attach/detach messages and the ability to list connected users and what mode they’re in.

If you activate multi-host mode in the configuration file you can create new sockets, allowing different sessions with different users to be hosted on the same machine. You can also list all active sockets with `wemux list` and switch between them easily.

Even with just two people the attach/detach messages are useful. Hope you like it!

Thanks so much for sharing this! As we prepare to open a new office in Detroit, I have been looking for ways to simplify screen-sharing with tmux. I’ll give this a try soon and let you know how it goes. It looks promising.

The attach/detach messages sound particularly useful. What I have been doing is much more rudimentary. I simply have “[#(tmux list-clients | grep -c ”)]” in my status-right to show how many clients are currently connected to the session. I look forward to playing with wemux.