People occasionally ask me why tmux
is significantly better than screen
, and I end up mumbling the first few things that come to mind. This has yet to sway anyone. Here, then, are some things that I enjoy about using tmux
.
First, some terminology, so the rest of this makes any sense at all.
tmux
andscreen
, if you were not aware, are multiplexers—they let you run multiple terminals (or terminal programs) at the same time, switch between them, and disconnect or close your terminal without killing everything you were running. If you didn’t know this then you should probably stop now and poke around tmux’s site or something.- A session is a particular group of terminals owned by
tmux
(orscreen
). When you runtmux
bare, you get a new session. - A window is a numbered terminal inside a session.
- A pane is each compartment within a split window. (I lied above; a window might actually have several panes and thus several terminals. But a window is identified by one number.)
- An xterm is a single GUI terminal window (or tab). You may be using another terminal emulator, or you may be in a non-GUI virtual terminal; I’m using “xterm” as an umbrella term for all of these.
I’m also assuming that ^A
is your multiplexer trigger key, although tmux
defaults to the more awkward ^B
.
Works out of the box
Here’s my .screenrc
, fiddled by hand over the course of many months after I started using screen
.
1caption always "%{= kw}%?%-Lw%?%{Kw}%n*%f %t%?(%u)%?%{kw}%?%+Lw%? %=%{= dw} %H "
2
3# terminfo and termcap for nice 256 color terminal
4# allow bold colors - necessary for some reason
5attrcolor b ".I"
6# tell screen how to set colors. AB = background, AF=foreground
7termcapinfo xterm 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'
8# erase background with current bg color
9defbce "on"
What the fuck is any of this? The only real configuration here is the first line, which sets a fairly simple status bar. The rest is unreadable sludge picked off of Google to make terminals inside screen
work the same way as terminals outside it. I see this as a serious failing in the one core feature that defines a multiplexer: being invisible.
Some of this might not be necessary any more; maybe termcaps have been improved in the meantime. Part of the very problem is that I can’t know; the best I can do is delete bits of it and see if screen
still behaves correctly, assuming I remember all the quirks I was trying to fix in the first place. It’s 2012. I shouldn’t ever see the word “termcap”.
Contrast with tmux
, which just worked. The only terminal-related fudging I ever had to do was set my $TERM
to xterm-256color
for it to respect 256-color sequences. Not entirely unreasonable.
tmux
can also inherit parts of the environment when it’s detected a change; by default it looks for some common X and SSH stuff. The upshot of this is that your SSH agent continues to work across SSH connections; the new environment only applies to newly-created windows, but zero hacks are necessary.
By default as of tmux
1.6 (I think), when you create a new window, it’ll get the same current working directory as the current window.
The status bar
If you run screen
with no .screenrc
, you get what looks like a regular terminal—you can’t even easily tell that you’re in a multiplexer, save for any terminal-related weirdness.
If you run tmux
with no .tmux.conf
, you get a status bar listing all your windows, as well as the name of the session and a timestamp.
Sure, you can just paste a line you find on the Web (like mine above, even!) into your .screenrc
and fix this instantly. But look at that line: what if you want to change a color? Can you even tell which of those escapes is a color? I wrote the damn thing and I couldn’t tell you.
Here’s an excerpt of the status bar configuration from my .tmux.conf
:
1# Status bar has a dim gray background
2set-option -g status-bg colour234
3set-option -g status-fg colour0
4# Left shows the session name, in blue
5set-option -g status-left-bg default
6set-option -g status-left-fg colour74
High xterm color names are not particularly friendly, and the actual contents of each part of the status bar are still controlled by special escapey codes. But you can tell what’s going on, and you can customize it yourself with relative ease. You can even change these settings from within tmux
itself and see the changes live.
xterm window title
How do you customize the xterm title in screen
? According to the FAQ:
1termcapinfo xterm*|rxvt*|kterm*|Eterm* 'hs:ts=\E]0;:fs=\007:ds=\E]0;\007'
2defhstatus "screen ^E (^Et) | $USER@^EH"
3hardstatus off
Ah! it’s our old friend termcap, followed by line noise. The FAQ entry indicates that this doesn’t really set the xterm title, but uses an obscure terminal feature known as a hard status line, and tells screen
to update the hard status line by using the xterm escapes that actually change the xterm title.
Let’s compare to my take on this for tmux
:
1set-option -g set-titles on
2set-option -g set-titles-string '[#S:#I #H] #W'
That gives you something like [blog:3 perushian] source/_posts/2012-03-21-tmux-is-sweet-as-heck.markdown
. #W
, meaning “window name”, uses the same special xterm escape sequence screen
invented to set the window name, so my .vimrc
and .zshrc
spit out custom window titles that work under either multiplexer. (Though, strangely, screen
‘s own invention never worked for me very reliably in screen
.)
Splits
screen
could only split horizontally when I used it, but it appears it recently learned to split vertically as well. I can’t speak to how well this works; I never actually used its splits. It seems the only default keybinding for switching between panes is ^A tab
.
In tmux
, ^A "
will split horizontally, and ^A %
will split vertically. Your current pane is outlined in green. ^A arrow
will move to the next pane in that direction. ^A ctrl-arrow
will resize the current pane in that direction; ^A alt-arrow
will resize five cells at a time.
You can tell tmux
to use a particular “layout”, which is a general approach it’ll use for determining sizes of panes. ^A alt-1
through 5 will rearrange all your panes (even the split direction) to fit one of the five builtin layouts. It’s great if you don’t care about the actual sizes of the panes, which I generally don’t 8)
Shuffling things around
If you attach to an existing session without detaching it, you’ll just attach to it twice. Both xterms will control the same session; it’ll have the same current window and pane, and changes to a pane will be reflected in both xterms. If a session is smaller than its containing xterm, tmux
will draw a border and a field of dots in the unused space.
It gets better! tmux new-session -t <existing-session>
will create a new session grouped with the one you name. They’ll share the same set of windows—close or create a window in either session, and you’ll see it in the other. But each session can have a different current window, so your two xterms can work on two things in one session at the same time.
For finer-grained control, tmux link-window -s foo:1 -t bar:2
will create a new window at position 2
in the session named bar
. This window will control the same set of panes, with the same terminals and processes, as window 1
in the session named foo
.
tmux break-pane -t <pane>
removes a pane from its window and sticks it into a new window. tmux join-pane -t <pane>
is the reverse operation: it splits the current window and uses an existing window as the new pane.
There are similar commands for rearranging panes and windows. Anywhere you refer to a pane or window, you can refer to a pane or window in an arbitrary session as well, so you can move whatever you want to wherever you want.
Miscellaneous
In tmux
, ^A pgup
enters copy mode and scrolls up a page, which is usually what I wanted anyway. In screen
, I always had to ^A esc
to enter copy mode, then pgup
. (I didn’t know how to change the key combination timeout at the time, either, so sometimes I’d type too fast and that just wouldn’t work.)
All tmux
key bindings are just regular commands. Anything you can do with a keybinding, you can do from tmux
‘s command line, or from running tmux <command>
regularly from a terminal—either inside or outside tmux
. (A handful of commands only work from inside tmux
, but these are interactive commands that rely on tmux
having control over the terminal.) You can script pretty much anything with ease.
One caveat to tmux
: while every screen
session is its own process, tmux
invisibly runs a master server that handles every pane in every session owned by your user. This lets the stuff in the previous session work. The only real impact of this is that if the server crashes, all your sessions go down with it. Thankfully, this tends not to happen.
The manpage is excellent and thorough. Most anything you may want to do can probably be accomplished with an obviously-named option or command.
Some other stuff from my .tmux.conf
that you may find useful:
Use ^A
as the magic keybinding:
1set-option -g prefix C-a
2unbind-key C-b
3bind-key a send-prefix
Bind ^A space
to switch to the next window to the right, ^A ctrl-space
to switch to the next window to the left, and ^A ^A
to switch to the last-used window:
1bind-key C-a last-window
2bind-key Space next-window
3bind-key C-Space previous-window
Set the esc/alt disambiguation timeout to 50ms. The default is half a second, which makes vim kind of painful.
1set-option -sg escape-time 50
Start numbering windows at 1, not 0. I like the leftmost window to be the leftmost number on my keyboard.
1set-option -g base-index 1
Set TERM=screen-256color
in new windows. (tmux
doesn’t have its own $TERM
; it hijacks the screen
family, so whatever recognizes screen
should recognize tmux
.)
1set-option -g default-terminal screen-256color
Tell tmux
to use xterm sequences for, e.g., ctrl-arrow. I don’t know why this isn’t on by default. If odd key combinations aren’t working for you, this is probably why.
1set-window-option -g xterm-keys on # to make ctrl-arrow, etc. work
Feel free to steal my color scheme, too. It’s simple, but a bit less glaring than the 70’s black-on-green that you get by default.
Now, go forth and multiplex! I am hilarious.