As a web developer, most of my time is spent in a command prompt banging away at web code. One of the greatest discoveries I have made to my productivity is the use of GNU Screen. It’s hard to distill the many benefits of a terminal window manager like this into a few bullet points, so here is my best shot:
Some quick Googling will provide a more exhaustive list, but these are my main favorites. For anyone curious, here is my .screenrc file on GitHub
But GNU Screen is just one of many programs that accomplish the same task. I found that tmux was another terminal window manager, thought I’d give it a shot!
I’ve been a happy GNU Screen user for about 2.5 years, but I am always looking for ways to improve my development process. I came across an article linked on HackerNews discussing tmux as a GNU Screen Killer. I’m not a fan of such a sensationalist title, but I thought it was worth evaluating.
I figured I would also document my experience here because I often find a lack of beginner documentation for many *nix based command line utilities. Most hardcore nerds just reply, “Just read the man pages n00b!” which I find to be disappointing as a first-time user. If I spend my first hour using some new technology just trying to get it set up and learn the ropes, I am liable to simply give up on it and decide it’s not worth my time – and I am a persistent bugger. If I can help one new user get up to speed a bit faster, using my first-time experiences as a stepping stone, mission accomplished.
My primary development machine is a Mac, and I use the fantastic HomeBrew as my package manager of choice. (Highly recommended over MacPorts!) This makes my installation very easy:
$ brew install tmux
And that’s it! Typing tmux
in the command line launches it.
My first step was to get my initial configuration all set up. To do so, I first create a file called .tmux.conf in my home directory:
$ touch ~/.tmux.conf
Now, I jump in with my favorite editor (go emacs!) and set up a few basics. Through some experimentation and playing, I got my initial file set up which I’ll paste here then explain:
set -g status on
set -g status-keys emacs
set -g history-limit 1000000
set -g prefix C-t
set -g status-bg green
setw -g window-status-current-bg cyan
setw -g window-status-current-attr bold
set -g status-right '#7H | %F %s'
bind-key C-t last-window
setw -g monitor-activity on
set -g visual-activity on
The first couple lines turn the status bar on and set my keybindings to emacs. There are also vi keybindings available. The status bar is one of the main benefits of using tmux. In GNU Screen, it was quite a task to get the status bar working. Below I’ve pasted the .screenrc configuration line to get the status bar working:
hardstatus string '%{= kG}[ %{G}%H %{g}[%{=kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%= %{g}][%{B}%Y-%m-%d %{W}%c %{g}]'
God help me if I ever had to change anything there! I can barely decipher what it’s doing! In contrast, the bit of my tmux config that accomplishes the same thing:
set -g status on
Ahhhhh. So, with tmux, just turning it on was much simpler and the default works exactly as I’d like so no customization was necessary.
The set -g history-limit 1000000
line sets the history limit very high so tmux
remembers everything I have done. The set -g prefix C-t
line changes the
keybinding to have Control-t be the keyboard command for all of tmux’s
commands. This had been my keybinding in GNU Screen and I liked it
because it didn’t conflict with anything I use in emacs. I rarely use
the transpose function and t is on my homerow (go Dvorak!). The default GNU Screen C-a
conflicted with the jump-to-beginning-of-line command in emacs which I had frequently used. The default in tmux is C-b
. More on this prefix command below.
The next 3 lines set the colors. I want the background of the status bar to be green and the currently active one to be cyan so it stands out.
The set -g status-right '#7H | %F %s'
line sets some attributes for the status bar. I found it a bit difficult to get a straightforward enumeration of what
all possibilities were, but the \#7H
shows the name of the machine I
am using, the %F
is the date in the form Y-M-D, and the %s
puts the
unix time, which is seconds since 1970. This is always useful for
database and other things which use that. There are many other things
which could be added to this status bar, but these are a few I found
useful.
The bind-key C-t last-window
line makes it so when I just type C-t
twice, it
jumps to the last window I was using for easy switching and the last 2
lines set visual activity on so when something happens in a window other
than my current one, I get a visual notification.
There are many more things that could go in a configuration file, but this gets me set up and going quickly and easily with my familiar keybindings.
First, you can just start tmux by typing the command and hitting enter:
$ tmux
But then your session has no name. This is ok, but it makes it more difficult to reattach later. To start a session with a name, start it with the following command:
$ tmux new-session -s {session-name}
Where {session-name}
is any name you want to give to your session. Then,
to reattach it later, if you disconnect from the server running tmux or
just decide to detach it for any other reason, just run:
$ tmux attach-session -t {session-name}
To attach the session which was previously open. Try it. Open a terminal
window, run tmux new-session -s test
, type some stuff into the command
prompt, then close the terminal window. Don’t worry, it’s not gone. Open
up another terminal window and run tmux attach-session -t test
and
you’ll be back up and running with your commands still entered.
Above, I rebound my prefix to C-t
. The default in tmux is C-b
. This
means you type it and, regardless of what program or window you are in,
anything that follows is a global command to tmux, superseding the
underlying window. This is why I chose C-t
, because C-b
is frequently
used by me in emacs and I didn’t want to change it. If you look at the
man page for tmux, you can see a full list of commands. They all
assume the prefix command has come first. This confused me a bit at
first because I thought those were all commands I could type from tmux,
but they all needed the prefix command first, then the command. Note,
from here on out, I’ll use C-b
to denote the prefix command because it’s
the default and likely more useful to most people than my C-t
rebinding.
So to use any of those keybindings from the man page, type your prefix
command (C-b
) then the key. For example, when it says t – Show the
time. it actually means C-b, t
which is typing Control-b (or your
rebound prefix key) then the t key.
On that same man page, further down, there are a bunch of word commands
such as source-file and list-commands. These can be bound to keys,
but they can also be called ad-hoc. This is like M-x
in emacs or vi’s :.
Simply type your prefix command such as C-b
, then type a colon (:) and,
where the status bar was, these arbitrary commands can now be typed. For
example:
C-b, :, list-commands
Will show you all of the available commands. These arbitrary commands can also be bound by adding the following to the .tmux.conf file:
bind-key C-l list-commands
This will bind C-l
to the list-commands command. So, typing your
prefix key C-b
then that C-l
will launch the list of commands
without the need to type it out. (this command, by default, is already
bound to ? so this is a bit of an unnecessary example)
In the subsection above about attaching a session, I suggested that you close your terminal window to detach the session. That is however unnecessary. It is easy to just detach a session from within tmux without closing the terminal window by typing:
C-b, d
d
for Detach.
So you’ve started tmux, but you only have a single window. Much of the discussion above assumes multiple active windows. To create a new window, just type:
C-b, c
c
for create. A new window is created and currently active. Look at the
status bar and there is now a new numbered window. There is no
(reasonable) limit to the number of windows created. Now, to kill the
currently selected one, just type:
C-b, &
Then confirm.
There are many ways to jump between currently active windows. The first
is just to type the prefix command, C-b, then a number. This will jump
to the selected window. For example, C-b, 1
jumps to window 1, C-b,
0
jumps to window 0.
C-b, {number}
To jump to the last selected window:
C-b, l
That’s l
as in lion. In my configuration, I rebound it to my prefix
command so I just type my prefix twice. This is my most frequently used
command, so I gave it the easiest shortcut.
The commands:
C-b, n
C-b, p
n
for next, p
for previous. Jump between the next and previous windows
respectively. It wraps so if the last window is currently selected and
the next command is issued, it will jump to the first window.
It is also possible to get a list of all windows and choose between them:
C-b, w
w
for windows. This is great if there are many windows opened. The
status bar can only show so many titles, so this view is often useful if
titles are long or there are many open windows.
This is one of my favorite features in tmux that I have discovered. This command actually allows for finding text in a given window and switching to that window. If multiple windows contain that text, a dialog is displayed for choosing the window.
C-b, f, {search string}
f
for find. Any search string can be entered and tmux will search each
of the windows for the appearance of that string and jump to the window
that contains that string.
In tmux, there is a distinction made between windows and panes. Windows are what appear along the bottom status bar. However, there is also talk of panes in the man file. So is a pane different from a window one may wonder?
Yes. The difference however is quite simple. Each thing along the status bar is a window. Each window consists of one or more panes, just like a real physical window. By default, it is a single pane, but it could have more. One of the strong benefits of tmux is the ability to split a window into multiple panes and work with each of them. More detailed discussion on panes below. Killing a pane kills just that pane and does not kill the window unless it is the last remaining pane in that window.
q
dismisses tmux dialogsIf you want to see a list of commands available to you, type C-b, :,
list-commands
and hit enter. To make that list disappear and go back to
where you were, just hit the q
key. This use of the q
key to jump
out of any tmux dialog is consistent, so it also works for any other
commands. To try another, type C-b, t
to view the current time. Typing
q
closes the time.
When I first tried using tmux and getting my configuration set up, I was
entering it using tmux
, seeing how it looked, quitting it with the
exit command, editing the configuration file, then relaunching it. I
thought, “there has got to be a better way, like source for tmux”
There is. Just run:
C-b, :, source-file, ~/.tmux.conf
And the configuration is reloaded in place! Now there is no reason to leave tmux to reload it.
One of the things I always found a bit kludgy was the way GNU Screen dealt with copy-past between buffers. I have a cheat sheet taped to my monitor for just this. In tmux, things seem a bit more straightforward and more powerful as tmux maintains a buffer so you can copy multiple things and access each thing you copied later! So you can copy Thing A, Thing B, Thing C, then go paste Thing B, Thing A, Thing C if you want. Very cool.
So, to jump into copy mode, type:
C-b, [
You’ll see now you can move your cursor up and down the current window
using your keybindings of choice (for emacs, it’s C-p
for previous line,
C-n
for next line, M-v
for page up, C-v
for page down). When you get the
cursor to where you want to start copying, hit the space bar to start
the selection. Then move to the end of what you want to copy and use the
command to wipe in emacs (C-w
) and the text is copied! Now is where the
magic starts. To paste the last thing copied, just type:
C-b, ]
But, to get to the whole buffer of what has previously been copied, type:
C-b, =
The copy buffer is now displayed. Just highlight the thing to be pasted
and hit enter to paste it. As with any dialog in tmux, q
will also
just dismiss the dialog.
So, you want to split your window to have an editor in the top and a command prompt in the bottom. No problem with tmux!
In any window, just type:
C-b, "
That’s a double-quote and it’ll split that window into 2 panes! Now, to move the cursor between the panes:
C-b, o
To kill a pane, just type:
C-b, x
It’s easy to open an editor in one and use the other like a terminal. There are many advanced features in tmux for getting the panes specifically configured a certain way, but that would merit its own treatment entirely. My favorite little trick though is to create a few panes and use:
C-b, space
This jumps through a set of default pane configurations, one of which almost always suits my needs.
This is just the tip of the iceberg, there are many other features in tmux, but at the start, I see a lot I like. It seems a lot like the next generation of GNU Screen which, sadly, has been mostly stagnant for many years. tmux gets a lot of things right like the configuration, the status bar and its use of panes. All of these things, while technically possible in GNU Screen, require a PhD in GNU Screen configuration, a task for which mere mortals are unequipped. I’ll keep using tmux for awhile to see how it goes, but it already has all the functionality of GNU Screen with basically the same keybindings (with a bit of conf file tweaking) and it has many additional features without dropping anything I use from the feature set of GNU Screen.
Thus far, I have to give tmux a big thumbs up!
Update September 25, 2014: If you enjoyed this, I expanded upon it greatly into a whole book on tmux! It’s called Getting Started with tmux and is available through Packt Publishing.