tmux describes itself as a “terminal multiplexer”. Pleasantly, it goes on to explain what that means:

It lets you switch easily between several programs in one terminal, detach them (they keep running in the background) and reattach them to a different terminal. And do a lot more.

The way I would describe it is that tmux runs terminal sessions independently of the terminal window you’re viewing those sessions in. This means that you can do some work in a tmux session, close the terminal window, or “detach” from the tmux window, and later reattach to the tmux session and find your work, tmux windows, and tmux panes exactly as you left them.

tmux windows and panes1 are the other features I really appreciate about tmux, in addition to the great ability to detach and close terminal windows without killing the work or processes running in the tmux session. Each pane within each window is a separate shell session.

I’ve been using tmux for a few years (I think), but until recently, my use had reached a plateau: I would manually start a tmux session, and start creating windows and manually splitting them into panes as I need for my work. When done, I would, inefficiently, start entering a bunch of exit commands to close all the panes one by one, until closing the last one kills the tmux session.

I was setting up a complicated workspace for simplestatistics when I thought to look into the possibility of writing a script that I could run to set up all the windows and panes I need. Unsurprisingly, it is possible, and great.

This is the finished simplestatistics tmux workspace script in its current form. You can find an up-to-date version of it here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# !/usr/local/bin/fish

# detach from a tmux session if in one
tmux detach > /dev/null ^ /dev/null

# don't set up the workspace if there's already a simplestatistics session running
if tmux list-sessions -F "#{session\_name}" | grep -q "simplestatistics";
	echo "simplestatistics session already running"
else
# okay no simplestatistics session is running

cd ~/projects/simplestatistics
tmux new -d -s simplestatistics

# window 0 - main
tmux rename-window main

# set up window 1 - documentation
# - index.rst
# - README.md
# - __init__.py
# fourth empty pane
tmux new-window -n documentation

tmux split-window -h -p 45
tmux select-pane -t 0
tmux split-window -v
tmux select-pane -t 0
tmux send-keys "cd ~/projects/simplestatistics/simplestatistics/" C-m
tmux send-keys "vim __init__.py" C-m

tmux select-pane -t 1
tmux send-keys "cd ~/projects/simplestatistics/" C-m
tmux send-keys "vim README.md" C-m

tmux select-pane -t 2
tmux send-keys "cd ~/projects/simplestatistics/simplestatistics/" C-m
tmux send-keys "vim index.rst" C-m
tmux split-window -v

# set up window 2 - changelogs
tmux new-window -n changelogs
tmux send-keys "cd ~/projects/simplestatistics/" C-m
tmux send-keys "vim changelog.txt" C-m

tmux split-window -h
tmux send-keys "cd ~/projects/simplestatistics/" C-m
tmux send-keys "vim HISTORY.rst" C-m

# back to window 0 - main
# 2 vertical panes: both will be used to edit main statistics functions
tmux select-window -t 0
tmux send-keys "cd ~/projects/simplestatistics/simplestatistics/statistics" C-m
tmux send-keys "ls" C-m
tmux split-window -h
tmux send-keys "cd ~/projects/simplestatistics/simplestatistics/statistics" C-m

tmux select-pane -t 0
tmux split-window -v
tmux send-keys "cd ~/projects/simplestatistics" C-m
tmux send-keys "bpython" C-m
tmux select-pane -t 0

tmux attach-session -t simplestatistics
end

If you attempt to start a session within a session, tmux warns you that sessions should be nested with care, and nesting sessions is not something I want to do anyway, but I want the ability to start session Y and attach to it while in session X. So lines 3 ➝ 4 attempt to detach from a tmux session, and sends normal and error output to /dev/null. If I’m attached, it detaches me before creating the session, and if I’m not, it fails silently.

Lines 6 ➝ 9 check to see if there’s already a running session named simplestatistics and stop execution with a message that reads "simplestatistics session already running" if it does find it.

Lines 12 ➝ 65 do the work of creating the workspace, which is made up of three windows.

window 1 - documentation

The second window (tmux windows are zero-indexed) contains the panes I use to edit and generate documentation for simplestatistics. The right pane is created with 45% of the window width.

Clockwise from top left:

  • __init__.py To add the new function I’m working on.
  • index.rst The main documentation page for Sphinx.
  • README.md
  • A shell for generating documentation.

window 2 - changelogs

Opens two versions of the changelogs in vim:

  • changelog.txt A Markdown-based changelog for all reasonable persons and machines.
  • HISTORY.rst A restructured version for PyPi.

window 0 - main editing

The layout is a bit unusual. The top left and entire right are listings of the directory that contains the function files. I use the big right pane to work on the new function, and the left one for general shell work and references.

The bottom left pane runs bpython for interactive testing.

Closing notes

If you work in the terminal and don’t use tmux, consider using it. It’s so nice to have several workspaces that never die until you kill them. If you do use tmux and often end up with complicated workspaces, consider scripting them!

  1. The terminology here is confusing: windows are actually tabs, their names appear at the bottom of the window, and they contain panes arranged in different layouts. It would make more sense to rename windows ➝ tabs, and rename panes ➝ windows.