The Tao of tmux

Foreword

Nearly all my friends use tmux. I remember going out at night for drinks and the 3 of us would take a seat at a round table and take out our smart phones. This was back when phones still had physical “QWERTY” keyboards.

Despite our home computers being asleep or turned off, our usernames in the IRC channel we frequently visited persisted in the chatroom list. Our screens were lit by a kaleidoscope of colors on a black background. We ssh’d with ConnectBot into our cloud servers and reattached by running screen(1). Just as it hit 2AM, our Turkish coffee arrived, the |away status indicator trailing our online nicknames disappeared.

It was funny that, even though we knew each other by our real names, we sometimes opted to call each other by our nicks. It’s something about how personal relationships, formed online, persist in real life.

It seemed as if it were orchestrated, but each of us fell into the same ebb and flow of living our lives. No one told us to do it, but bit by bit, we incrementally optimized our lifestyles, personally and professionally, to arrive at destinations that felt eerily alike.

Like many things in life, when we act on autopilot, we sometimes arrive at similar destinations. This is often unplanned.

So, when I write an educational book about a computer application, I hope to write it for human beings. Not to sell you on tmux, convince you to like it or hate it, but to tell you what it is and how some people use it. I’ll leave the rest to you.

I’ve helped thousands learn tmux through my free resource under the name The Tao of tmux, which I kept as part of the documentation for the tmuxp session manager. And now, it’s been expanded into a full-blown book with refined graphics, examples, and much more.

You do not need a book to use or understand tmux. If you want a technical manual, look at the manpage for tmux. Manpages, however, are rarely sufficient to wrap your brain around abstract concepts; they’re there for reference. This learning book is the culmination of years of explaining tmux to others online and in person.

In this book, we will break down tmux by the way of its objects, from servers down to panes. It also includes a rehash of terminal facilities we use every day to keep us autodidacts up to speed with what is what. I’ve included numerous examples of projects, permissively licensed source code, and workflows designed for efficiency in the world of the terminal.

tmux is a tool I find useful. While I don’t attach it to my personal identity, it’s been part of my daily life for years. Besides the original resource, I’ve written a popular tmux starter configuration, a pythonic tmux library, and a tmux session manager.

I am writing this from vim running in a tmux pane, inside a window, in a session, on the server, through a client.

A word to absolute beginners: Don’t feel you need to grasp the concepts of the command line and terminal multiplexing in a single sitting. You have the choice of picking out concepts of tmux you like, according to your needs or interests. If you haven’t installed tmux yet, please view the Installation section in the Appendix of the book.

Styles

Formatted text like this is source code.

Formatted text with a $in front is a terminal command. $ echo 'like this'. This means you type that text right into the console, without the dollar character. For more information on the meaning of the “dollar prompt”, check out What is the origin of the UNIX $(dollar) prompt? on Super User. Shortcuts require a prefix key to be sent beforehand. Sections describing similar keyboard commands typically will appear in a table. For example: Shortcut Action Prefix + d Detach client from session. How this book is structured First, anything involving installation and hard technical details are in the Appendix. A lot of books use installation instructions as filler in the early chapters. For me, it’s more of not wanting to confuse beginners. For special circumstances, like tmux on Windows 10, I decided adding screenshots is best, since many readers may be more comfortable with a visual approach. Thinking Tmux goes over what tmux does and how it relates to the GUI desktops on our computers. You’ll understand the big picture of what tmux is and how it can make your life easier. Terminal Fundamentals shows the text-based environments you’ll be dealing with. It’s great for those new to tmux, but also presents technical background for developers, who learned the ropes through examples and osmosis. At the end of this section, you’ll be more confident and secure using the essential components underpinning a modern terminal environment. Practical Usage covers common bread and butter uses for you to use tmux immediately. Server gives life to the unseen workhorse behind the scenes that powers tmux. You’ll think of tmux differently and may be impressed that a client-server architecture could be presented to end users so seamlessly. Sessions are the containers holding windows. You’ll learn what sessions are and how they help organize your workspace in the terminal. You’ll learn how to manipulate and rename and traverse sessions. Windows are what you see when tmux is open in front of you. You’ll learn how to rename and move windows. Panes are a terminal in a terminal. This is where you get to work and do your magic! You’ll learn how to create, delete, move between, and resize panes. Configuration discusses customization of tmux and sets the foundation for how to think about .tmux.conf so you can customize your own. Status bar is devoted singularly to the customization of the status line in tmux. You’ll even learn how to show CPU and memory usage via the status line. Scripting tmux goes into command aliases and the advanced and powerful Targets and Formats concepts. Technical Stuff is a glimpse at tmux source code and how it works under the hood. You may learn enough to impress colleagues who already use tmux. If you like programming on Unix-like systems, this one is for you. Tips and Tricks wraps up with a whirlwind of useful terminal tutorials you can use with tmux to improve day to day development and administration experience. Cheatsheets are organized tables of commands, shortcuts, and formats grouped by section. Donations If you enjoy my learning material or my open source software projects, please consider donating. Donations go directly to me and my current and future open source projects and are not squandered. Visit http://www.git-pull.com/support.html for ways to contribute. Formats This book is available for sale on Leanpub and Amazon Kindle. It’s also available to read for free on the web. Errata This is my first book. I am human and make mistakes. If you find errors in this book, please submit them to me at tao.of.tmux <AT> nospam git-pull.com. You can also submit a pull request via https://github.com/git-pull/tao-of-tmux. I will update digital versions of the book with the changes where applicable. Thanks Thanks to the contributors who helped me spot errors in this book. Some copy, particularly in cheatsheets, comes straight out of the manual of tmux, which is ISC-licensed. Book Updates and tmux changes This book was written for tmux 2.3, released September 2016. As of January 2017, it’s trivial to push out minor changes to Leanpub. Kindle is harder. tmux does intermittently receive updates. I’ve accommodated many over the past 5 years on my personal configurations and software libraries set with continuous integration tests against multiple tmux versions. Sometimes, publishers overplay version numbers to make it seem as if it’s worth striking a new edition of a book over it. It’s effective for them, but I’d rather be honest to my readership. If you’re considering keeping up to date with new features and adjustments to tmux, the CHANGES file in the project source serves as a way to see what’s updated between official releases. 1. Thinking in tmux In the world of modern computing, user interaction has 2 realms: 1. The text realm 2. The graphical realm tmux lives in the graphical realm in which fixed-width fonts appear in a rectangular grid in a window, like in a terminal from the 1980s. Window manager for the terminal tmux is to the console what a desktop is to GUI apps. It’s a world inside the text dimension. Inside tmux, you can: • multitask inside the terminal, run multiple applications • have multiple command lines (pane) in the same window • have multiple windows (window) in the workspace (session) • switch between multiple workspaces, like virtual desktops tmux “Desktop”-Speak Plain English Multiplexer Multi-tasking Multiple applications simultaneously. Session Desktop Applications are visible here Window Virtual Desktop or A desktop that stores it own screen applications screen Pane Application Performs operations Just like in a graphical desktop environment, they throw in a clock, too. Multitasking tmux allows you to keep multiple terminals running on the same screen. (After all, that’s where the abbreviation “tmux” comes from - Terminal Multiplexer.) In addition to multiple terminals on one screen, tmux allows you to create and link multiple “windows” within the confines of the tmux session you attached. Even better, you can copy and paste and scroll. No requirement for graphics either, so you have full power, even if you’re SSH’ing or on a system without X. Here are a few common scenarios: • Running tail -F /var/log/apache2/error.log in a pane to get a live stream of the latest system events. • Running a file watcher, like watchman, gulp-watch, grunt-watch, guard, or entr. On file change, you could do stuff like: • Keeping a text editor, like vim, emacs, pico, nano, etc. open in a main pane, while leaving two other open for CLI commands and building via make or ninja. With tmux, you quickly have the makings of an IDE! And on your terms. Keep your applications running in the background Sometimes, GUI applications will have an option to be sidelined to the system tray to run in the background. The application is out of sight, but events and notifications can still come in, and the app can be instantly brought to the foreground. In tmux, a similar concept exists, where we can “detach” a tmux session. Detaching can be especially useful on: • Local machines. You start all your normal terminal applications within a tmux session, you restart X. Instead of losing your processes as your normally would if you were using an X terminal, like xterm or konsole, you’d be able to tmux attach after and find all processes that were alive and kicking all along. • Remote SSH applications and workspaces you run in tmux. You can detach your tmux workspace at work before you clock out, then the next morning, reattach your session. Ahhh. Refreshing. :) • Those servers you rarely log into. It could be that cloud instance you have that you log into 9 months later, and as a reflex, tmux attach to see if there is anything on there. And boom, you’re back in a session that’s 9 months old. It’s like a hack to restore your short-term memory. Powerful combos Chatting on irssi or weechat, one of the “classic combos”, along with a bitlbee server to manage AIM, MSN, Google Talk, Jabber, ICQ, even Twitter. Then, you can detach your IRC and “idle” in your favorite channels, stay online on instant messengers, and get back to your messages when you return. Some keep development services running in a session. Hearty emphasis on development, you probably will want to daemonize and wrap your production web applications, using a tool like supervisor, with its own safe environmental settings. You can also have multiple users attach their clients to the same sessions, which is great for pair programming. If you were in the same session, you and the other person would see the same thing, share the same input, and the same active window and pane. The above are just examples, but any general workspace you’d normally use in a terminal for any task can gain the benefit of you being able to persist it! That includes projects or repetitive efforts you’d multitask on. The tips and tricks section will dive into specific flows you can use today. Summary tmux is a versatile addition to your terminal toolbelt. It helps you cover the gaps between multitasking and workspace organization you’d otherwise lose, since there’s no GUI. In addition, it includes a nice ability to detach workspaces to the background and reattach later. In the next chapter, we will touch on some terminal basics before diving deeper into tmux. 2. Terminal fundamentals Before getting into tmux, a few fundamentals of the command line should be reviewed. Often, we’re so used to using these out of street smarts and muscle memory, a great deal of us never see the relation of where these tools stand next to each other. Seasoned developers are familiar with zsh, Bash, iTerm2, konsole, /dev/tty, shell scripting, and so on. If you use tmux, you’ll be around these all the time, regardless whether you’re in a GUI on a local machine or SSH’ing into a remote server. If you want to learn more about how processes and TTY’s work at the kernel level (data structures and all), the book The Design and Implementation of the FreeBSD Operating System (2nd Edition) by Marshall Kirk McKusick is nice, particularly, Chapter 4, Process Management and Section 8.6, Terminal Handling. The TTY demystified by Linus Åkesson (available online) dives into the TTY and is a good read. Much more exists to glean off the history of Unix, 4.2 BSD, etc. I probably could have a coffee / tea with you discussing it for hours. You could look at it from multiple perspectives (The C Language, anything from the Unix/BSD lineage, etc.), and some clever fellow would likely chime in, mentioning Linux, GNU, and so on. It’s like Game of Thrones; there’s multiple story arcs you can follow, some of which intersect. A few good video resources would be A Narrative History of BSD by Marshall Kirk McKusick, The UNIX Operating System by AT&T, Early days of Unix and design of sh by Stephen R. Bourne. POSIX stuff Operating systems like macOS (formerly OS X), Linux, and the BSDs, follow something similar to the POSIX specification in terms of how they square away various responsibilities and interfaces of the operating system. They’re categorized as “Mostly POSIX-compliant”. In daily life, we often break compatibility with POSIX standards for reasons of sheer practicality. Operating systems, like macOS, will drop you right into Bash. make(1), a POSIX standard, is GNU Make on macOS by default. Did you know that, as of September 2016, POSIX Make has no conditionals? I’m not saying this to take a run at purists. As someone who tries to remain compatible in my scripting, it gets hard to do simple things after a while. On FreeBSD, the default Make (PMake) uses dots between conditionals: But on most Linux systems and macOS, GNU Make is the default, so they get to do: This is one of the many tiny inconsistencies that span across operating systems, their userlands, their binary / library / include paths, and adherence / interpretation of the Filesystem Hierarchy Standard or whether they follow their own. These differences add up. A good deal of software infrastructure out there exists solely to abstract the differences across them. For example: CMake, Autotools, SFML, SDL2, interpreted programming languages, and their standard libraries are dedicated to normalizing the banal differences across BSD-derivatives and Linux distributions. Many, many #ifdef preprocessor directives in your C and C++ applications. You want open source, you get choice, but be aware; there’s a lot of upkeep cost in keeping these upstream projects (and even your personal ones) compatible. But I digress, back to terminal stuff. Why does it matter? Why bring it up? You’ll see this stuff everywhere. So, let’s separate the usual suspects into their respective categories. Terminal interface The terminal interface can be best introduced by citing official specification, laying out its technical properties, interfaces, and responsibilities. This can be viewed in its POSIX specification. That’s your TTY’s, including text terminals and X sessions that live within them. On Linux / BSD systems, you can switch between sessions via <ctrl-alt-F1> through <ctrl-alt-F12>. Terminal emulators GUI Terminals: Terminal.app, iterm, iterm2, konsole, lxterm, xfce4-terminal, rxvt-unicode, xterm, roxterm, gnome terminal, cmd.exe + bash.exe Shell languages Shell languages are programming languages. Sure, you may not compile the code into binaries with gcc or clang. And there may not be a shiny npm for them, but a language is a language. Each shell interpreter has its own language features. Like with shells, many will resemble the POSIX shell language and strive to be compatible with it. Zsh and Bash should be able to understand POSIX shell scripts you write, but not the other way around (we will cover that in shell interpreters). The top of .sh files shebang statement, which can invoke shellscripts in different dialects. Zsh scripts are implemented by the Zsh shell interpreter, Bash scripts by Bash. But the languages are not as closely regulated and standardized as, say, C++’s standards committee workgroups or python’s PEPs. Bash and Zsh take features from Korn and C Shell’s languages, but without all the ceremony and bureaucracy that other languages entail. Shell interpreters (Shells) Examples: POSIX sh, Bash, Zsh, csh, tcsh, ksh, fish Shell interpreters implement the shell language. They are a layer on top of the kernel and are what allow you, interactively, to run commands and applications inside them. As of October 2016, the latest POSIX specification covers in technical detail the responsibilities of the shell. For shells and operating systems: each distro or group does their own darn thing. On most Linux distributions and macOS, you’ll typically be dropped into Bash. That’s because Apple decided to use it as a default shell for users. On FreeBSD, you may default to a plain vanilla sh unless you specify otherwise during the installation process. In Ubuntu, /bin/sh used to be bash (Bourne Again Shell) but was replaced with dash (Debian Almquist Shell). So, here, you are thinking “hmm, /bin/sh, probably just a plain old POSIX shell”; however, system startup scripts on Ubuntu used to allow non-POSIX scripting via Bash. This is because specialty shell languages, such as Bash and Zsh, add a lot of helpful and practical features that may work on one interpreter, but not another. For instance, you would need to install the Zah interpreter across all your systems if you rely on Zsh-specialized scripting. If you conformed with POSIX shell scripting, your scripting would have the highest level of compatibility at the cost of being more verbose. Recent versions of macOS include Zsh by default. Linux distributions typically require you to install it via package manager and install it to /usr/bin/zsh. BSD systems build it via the port system, pkg(8) on FreeBSD, or pkg_add(1) on OpenBSD, and it will install to /usr/local/bin/zsh. It’s fun to experiment with different shells. On many systems you can use chsh -s to update the default shell for a user. The other thing to mention is, for chsh -s to work, you typically need to have it added to /etc/shells. Summary To wrap it up, you will hear people talking about shells all the time. Context is key. It could be: • A generic way to refer to any terminal you have open. “Type $ top into your shell and see what happens.” (Press q to quit.)
• A server they have to log into. Before the era of the cloud, it would be popular for small hosts to sell “C Shells” with root access.
• A shell within a tmux pane.
• If scripting is mentioned, it is likely either the script itself, the scripting issue at hand, or something about the shell language.

But overall, once you get out of this chapter, go back to doing what you’re doing. If shell is what people say and they understand it, use it. The backing you got here should make you more confident in yourself. It’s an ongoing battle, these days, to keep street smarts we pick up with book smarts.

In the next chapter, we will touch some terminal basics before diving deeper into tmux.

3. Practical Usage

This is the easiest part; open your terminal and type tmux, hit enter.

You’re in tmux.

The prefix key

The prefix is how we send commands into tmux. With this, we can split windows, move windows, switch windows, switch sessions, send in custom commands, you name it.

And it’s a hump we have to get over.

It’s kind of like Street Fighter. In this video game, the player inputs a combination of buttons in sequence to perform flying spinning kicks and shoot fireballs; sweet. As the player grows more accustomed with the combos, they repeat moves by intuition, since they grow muscle memory.

Without understanding how to send command sequences to tmux via the prefix key, you’ll be dead in the water.

Key sequences will come up later if you use Vim, Emacs, or other TUI (Terminal User Interface) applications. If you haven’t internalized the concept, let’s do it now. If you have done similar command sequences in TUI/GUI applications, that’ll come in handy.

When you memorize a key combo, it’s one less time you’ll be moving your hand away from the keyboard to grab your mouse. You can focus your short-term memory on getting stuff done; that means fewer mistakes.

The default leader prefix is <Ctrl-b>. That’s holding down the control key, then b.

You’ve detached the tmux session you were in. You can reattach via $tmux attach. Session persistence and the server model If you use Linux or a similar system, you’ve likely brushed through Job Control, such as fg(1), jobs(1). tmux behavior feels similar, like you ran <ctrl-z> except, technically, you were in a “job” all along. You were just using a client to view it. Another way of understanding it: <Ctrl-b> d closed the client connection, therefore, ‘detached’ from the session. Your tmux client disconnected from the server instance. The session, however, is still running in the background. It’s all commands Multiple roads can lead you to the same behavior. Commands are what tmux uses to define instructions for setting options, resizing, renaming, traversing, switching modes, copying and pasting, and so forth. • Configs are the same as automatically running commands via $ tmux command.
• Internal tmux commands via Prefix + : prompt.
• Settings defined in your configuration can also set shortcuts, which can execute commands via keybindings via bind-key.
• Commands called from CLI via $tmux cmd • To pull it all together, source code files are prefixed cmd-. Summary We’ve established tmux automatically creates a server upon starting it. The server allows you to detach and later reattach your work. The keyboard sequences you send to tmux require understanding how to send the prefix key. Keyboard sequences, configuration, and command line actions all boil down to the same core commands inside tmux. In our next chapter, we will cover the server. 4. Server The server holds sessions and the windows and panes within them. When tmux starts, you are connected to a server via a socket connection. What you see presented in your shell is merely a client connection. In this chapter, we go into one of the secret sauces that allow your terminal applications to persist for months or even years if you want to. What? tmux is a server? Often, when “server” is mentioned, what comes to mind for many may be rackmounted hardware; to others, it may be software running daemonized on a server and managed through a utility, like upstart, supervisor, and so on. Unlike web or database software, tmux doesn’t require specialized configuration settings or creating a service entry to start things. tmux uses a client-server model, but the server is forked to the background for you. Zero config needed You don’t notice it, but when you use tmux normally, a server is launched and being connected via a client. tmux is so streamlined, the book could continue to explain usage and not even mention servers. But, I’d rather you have a solid understanding that while, tmux feels like magic, it’s utilitarian. One cannot deny it’s exquisitely executed from a user experience standpoint. How is it utilitarian? We’ll go into it more in future chapters, where we dive into Formats, Targets, and tools such as libtmux that I made, which utilize these features. It surprises some, because servers often beget a setup process. But servers being involved doesn’t entail hours of configuration on each machine you run on. There’s no setup. When people think server, they think pain. It invokes an image of digging around /etc/ for configuration files and flipping settings on and off just to get basic systems online. But not with tmux. It’s a server, but in the good way. Stayin’ alive The server part of tmux is how your sessions can stay alive, even after your client is detached. You can detach a tmux session from an SSH server and reconnect later. You can detach a tmux session, stop your X server in Linux/BSD, and reattach your tmux session in a TTY or new X server. The tmux server won’t go away until all sessions are closed. Servers hold sessions One server can contain one or multiple sessions. Recurring usage of tmux, after a server already exists, will create a new session inside that server. How servers are “named” The default name for the server is default, which is stored as a socket in /tmp. The default directory for storing this can be overridden via setting the TMUX_TMPDIR environment variable. So, something like: Will give you a tmux directory created within your $HOME folder. On OS X, your home folder will probably be something like /Users/yourusername. On other systems, it may be /home/yourusername. If you want to find out, type echo $HOME. Clients Servers will have clients (you) connecting to them. When you connect to a session and see windows and panes, it’s a client connection into tmux. You can retrieve a list of active client connections via: These commands, as well as the other list- commands, in practice, are rather rare. But they are part of the tools that make tmux highly scriptable should you want to get creative. You can learn more about that in formats. Clipboard tmux clients wield a powerful clipboard feature to copy and paste across sessions, windows and panes. Much like vi, tmux handles clipboard as a mode (or a state) in which a pane is temporarily placed, in while text can be copied. The default key to enter copy mode is Prefix + [. 1. From within, use [space] to enter copy mode. 2. Use the arrow keys to adjust the text to be selected. 3. Press [enter] to copy the selected text. The default key to paste the text copied is Prefix + ]. Summary The server is one of the fundamental underpinnings of tmux. Mostly, it is invisible to the user. The server can hold one or more sessions. You can copy and paste between sessions via the clipboard. In the next chapter we will go deeper into the role sessions play and how they help you organize and control your terminal workspace. 5. Sessions Welcome to the session, the highest-level entity residing in the server instance. Server instances are forked to the background upon starting a fresh instance and reconnected to when reattaching sessions. Your interaction with tmux will have at least one session running. A session holds one or more windows. The active window will have a * symbol next to it. Creating a session The simplest command to create a new session is typing tmux: The $ tmux application, with no commands is equivalent to $tmux new-session. Nifty! By default, your session name will be given a number, which isn’t too descriptive. What would be better is: Switching sessions within tmux Some acquire the habit of detaching their tmux client and reattaching via tmux att -t session_name. Thankfully, you can switch to session from within tmux! Shortcut Action Prefix + ( Switch the attached client to the previous session. Prefix + ) Switch the attached client to the next session. Prefix + L Switch the attached client back to the last session. Prefix + s Select a new session for the attached client interactively. Prefix + s will allow you to switch between sessions within the same tmux client. This command name can be confusing. switch-client will allow you to traverse between sessions in the server. Example usage: This will switch to a session, named “dev”, if it exists. No need to enter the target-client if you’re already in a client. Naming sessions Sometimes, the default session name given by tmux isn’t descriptive enough. It only takes a few seconds to update it. You can name it whatever you want. Typically, if I’m working on multiple web projects in one session, I’ll name it “web”. If I’m assigning one software project to a single session, I’ll name it after the software project. You’ll likely develop your own naming conventions, but anything is more descriptive than the default. If you don’t name your sessions, it’ll be difficult to keep track of what is inside that session from the outside. Sometimes, you may forget you already have a project opened that is a few days old, and you can just re-attach or switch to that. You can rename sessions from within tmux with Prefix + $. The status bar will be temporarily altered into a text field to allow altering the session name.

Through command line, you can try:

Does my session exist?

If you’re scripting tmux, you will want to see if a session exists. has-session will return a 0 exit code if the session exists, but will report a 1 exit code and print an error if a session does not exist.

It assumes the session “1” exists; it’ll just return 0 with no output.

But if it doesn’t, you’ll get something like this in a response:

To try it in a shell script:

Summary

In this chapter, you learned how to rename sessions for organizational purposes and how to switch between them quickly.

You’ll always be attached to a session when you’re using a client in tmux.

One way that may help is to think of sessions as workspaces designed to help organize a set of windows. It’s analogous to virtual desktop spaces in GUI computing.

In the next chapter, we will go into windows, which, like sessions, are also nameable and let you switch between them.

6. Windows

Windows hold panes. They reside within a session.

They also have layouts, which can be one of many preset dimensions or a custom one done through pane resizing.

You can see the current windows through the status bar located at the bottom of tmux.

Creating windows

All sessions start with at least 1 window (and therefore one pane inside that) open. From there, you can create and delete windows as you see fit.

Window indexes are a number tmux uses to determine ordering. The first window’s index is 0, unless you set it via base-index in your configuration. I usually set -g base-index 1 in my tmux configuration since 0 is after 9 on the keyboard.

Prefix + c will create a new at the first open index. So if you’re in the first window, and there is no second window created yet, it will create the second window. If the second window is already taken, and the third hasn’t been created yet, it will create the third window.

If the base_index is 1, and there are 7 windows created, with the 5th window missing, creating a new window will fill the empty 5th index, since it’s the next one in order and nothing is filling it. After that, a new window would be the eighth.

Naming windows

Just like with sessions, windows can have names. Labelling them helps keep track of what you’re doing inside them.

When inside tmux, the most common way of doing that is Prefix + ,. This will open a prompt in the tmux status line, where you can alter the name of the current window.

Traversing windows

Moving around windows is often done in two ways. First, by iterating through via Prefix + p and Prefix + n, and via the window index, which takes you directly to a specific window.

Prefix + 1, Prefix + 2, and so on… will get you to navigate to windows by their index.

Prompt for a window index (useful for indexes greater than 9) with Prefix + '.

You can move to the last selected window with Prefix + l.

You can bring up a list of current windows with Prefix + w. The benefit of this is it also gives you some info on what’s inside the window. Helpful if you’re juggling around a lot of things!

Moving windows

Windows themselves can also be reordered one by one via move-window and its associated shortcut. This is helpful if a window is worth keeping open but not important or rarely looked at. After you move a window, you can continue to reorder them at any point in time after.

The command $tmux move-window can be used to move windows. The accepted arguments are -s (the window you are moving) and -t, where you are moving the window to. You can also use $ tmux movew for short.

Example: move the current window to number 2:

Example: move window 2 to window 1:

The shortcut to prompt for an index to move the current window to is Prefix + ..

Layouts

Prefix + space switches window layouts. These are preset configurations that handle proportions of panes.

As of tmux 2.3, the supported layouts are:

Specific touch-ups can be done via resizing panes.

Summary

In this chapter, you learned how to manipulate windows via renaming and changing their layouts. To top it off, some advanced functionality you can use to kill windows in a pinch or in shell scripting tmux. In addition, how to save any tmux layouts via outputting the window_layout template variable.

If you are in a tmux session, you’ll always have at least one window open, and you’ll be in it. And within that window will be a shell, or “pane”. When all the panes close, the window closes too! In the next chapter, we’ll go deeper into panes.

7. Panes

Panes are pseudoterminals that contain your shell (e.g. Bash, Zsh). They reside within a window. A terminal within a terminal, you can run shell commands, scripts, programs like vim, emacs, top, htop, irssi, weechat and so on from within them.

Creating new panes

To create a new pane, you can split-window from within the current window and pane you are in.

Shortcut Action
Prefix + % split-window -h (split horizontally)
Prefix + " split-window -v (split vertically)

You can continue to create panes until you’ve reached the limit of what the terminal can fit. This depends on the dimensions of your terminal. A normal window will usually have 1 to 5 panes open.

Example usage:

Traversing Panes

Shortcut Action
Prefix + ; Move to the previously active pane.
Prefix + Up / Change to the pane above, below,
Down / Left / to the left, or to the
Right the right of the current pane.
Prefix + o Select the next pane in the current window.

Zoom in

To zoom in on a pane, navigate to it and do Prefix + z.

You can use any pane traversal to unzoom and move a pane at the same time.

Resizing panes

Pane size can be adjusted within windows via window layouts and resize-pane. Adjusting window layout switches the proportions and order of the panes. Resizing the panes targets a specific pane inside that window.

Resizing a pane in a specific layout may subsequently resize that whole row.

Shortcut Action
Prefix M-Up resize-pane -U 5
Prefix M-Down resize-pane -D 5
Prefix M-Left resize-pane -L 5
Prefix M-Right resize-pane -R 5
Prefix C-Up resize-pane -U
Prefix C-Down resize-pane -D
Prefix C-Left resize-pane -L
Prefix C-Right resize-pane -R

Outputting pane to a file

You can output the display of a pane to a file.

The #I and #P are formats for window index and pane index, so the file created is unique. Clever!

8. Configuration

Configuration of tmux is managed through .tmux.conf in your $HOME directory. The paths ~/.tmux.conf and $HOME/.tmux.conf should work on OS X, Linux, and BSD.

For a sample config, I maintain a pretty decked out one at https://github.com/tony/tmux-config.

Updating configs in current sessions

You can apply config files in live tmux sessions. Compare this to source or “dot” in the POSIX standard.

Prefix + : will open the tmux prompt, then type:

:source /path/to/config.conf

And hit return.

$tmux source-file /path/to/config.conf can also achieve the same result via command line. How configs work The tmux configuration is processed just like run commands in a ~/.zshrc or ~/.bashrc file. bind r source ~/.tmux.conf in the tmux configuration is the same as $ tmux bind r source ~/.tmux.conf.

You could always create a shell script that prefixes tmux  in front of every entry and run that file on fresh servers. The result is the same. Same goes if you manually type in $tmux set-option and $ tmux bind-key commands into any terminal (in or outside tmux).

This in .tmux.conf:

Shell command output

You can also call applications, such as tmux-mem-cpu-load and conky, and powerline.

Styling

You can use [bg=color] and [fg=color] to adjust the text color and background within for status line text.

Prompt colors

The benefit of wrapping your brain around this styling is you will see it message-command-style, message style and so on.

Let’s try this:

So, you want to customize your tmux status line before you write the changes to your config file.

Start by grabbing your current status line section you want to edit, for instance:

Also, you can try to snip off the variable with | cut -d' ' -f2-:

Turn it off:

Turn it on:

Toggle it (regardless or current state):

Bind toggling status line to Prefix + q:

Example: Dressed up

Configs can print the output of an application. In this example, tmux-mem-cpu-load is providing system statistics in the right-side section of the status line.

To build tmux-mem-cpu-load, you have to install CMake and have a C++ compiler, like clang or GCC.

On Ubuntu, Debian, and Mint machines, you can do this via $sudo apt-get install cmake build-essential. On macOS w/ brew via $ brew install cmake.

Example: Powerline

By far, the most full-featured solution available for tmux status lines is powerline, which heavily utilizes the shell command outputs, not only to give direct system statistics, but also to generate tmux-friendly styling alongside emoji-like glyphs.

To get these to work correctly, set up your fonts up to handle the powerline symbols. The easiest way to use this is to install powerline fonts, which are a great collection of fixed width coder fonts that look great in terminal.

Installation instructions are on Read the Docs. For a better idea:

psutil is a cross-platform tool powerline uses to help gather system information.

The first option to get powerline working with tmux is sourcing powerline.conf from your config. The only difficulty is nailing down the location across systems and python versions. To try getting powerline found across varying installations, I use if-shell:

For a simpler approach, assure you properly configured python with your PATHs and try this:

10. Scripting tmux

The command line shortcuts and options in tmux is an area often uncharted.

I will use tables in this chapter. Never get a feeling you have to commit a table to memory immediately. Not my intention, but every person’s way of using tmux is slightly different. I want to cover points most likely to benefit people’s flows. Full tables are in the cheatsheets.

Aliases

tmux supports a variety of alias commands. So, don’t feel you always have to type tmux attach. Aliases, alongside fnmatch-style pattern commands, make it intuitive to type those commands in a pinch.

Most aliases come to mind via intuition and are a lot friendlier than typing the full hyphenated commands.

Command Alias
attach-session attach
break-pane breakp
capture-pane capturep
display-panes displayp
find-window findw
join-pane joinp
kill-pane killp
kill-window killw
last-pane lastp
last-window last
list-panes lsp
list-windows lsw
move-pane movep
move-window movew
new-session new
new-window neww
next-layout nextl
next-window next
pipe-pane pipep
previous-layout prevl
previous-window prev
rename-window renamew
resize-pane resizep
respawn-pane respawnp
respawn-window respawnw
rotate-window rotatew
select-layout selectl
select-pane selectp
set-option set
set-window-option setw
show-options show
show-window-options showw
split-window splitw
swap-pane swapp
swap-window swapw

If you know the full name of the command, if you were to chopped the hyphen (-) from the command and add the first letter of the last word, you’d get the shortcut, e.g., swap-window is swapw, split-window is splitw.

Pattern matching

tmux commands and arguments may all be accessed via fnmatch(3) patterns.

For instance, you need not type $tmux attach-session every time. First, there’s the alias of $ tmux attach, but besides that, you can pattern match $tmux attac, $ tmux att, $tmux at and $ tmux a work.

Every tmux command has shorthands; let’s try this for $tmux new-session: and so on, until: The limitation, as seen above, is that command matches can collide. Multiple commands begin with new-. So, if you wanted to use matches, $ tmux new-s for a new session or $tmux new-w for a new window would be the most efficient way. But the alias of $ tmux new for new session and $tmux neww for new windows is even better than the matching in that case. Targets If a command allows target specification, it’s usually done through -t. Think of targets as tmux’s way of specifying a unique key in a relational database. Entity Prefix Example server n/a n/a, uses socket-name and socket-path client n/a n/a, uses /dev/tty{p,s}[000-9999] session$ $13 window @ @2313 pane % %5432 What I use to help me remember: So, sessions are represented by dollar signs ($) because they hold your projects (ostensibly where you make money or help someone else do it).

Windows are represented by the at sign (@). So, windows are like referencing / messaging a user on a social networking website.

Panes are the fun one, represented by the percent sign (%), like the default prompt for csh and tcsh. Hey, makes sense, since panes are pseudoterminals!

To show you the possibilities of where you can use targets, here are some examples:

$tmux attach-session [-t target-session] $ tmux detach-client [-s target-session] [-t target-client]

$tmux has-session [-t target-session] $ tmux kill-session [-t target-session]

$tmux list-clients [-t target-session] $ tmux lock-client [-t target-client]

$tmux lock-session [-t target-session] $ tmux new-session [-t target-session]

$tmux refresh-client [-t target-client] $ tmux rename-session [-t target-session]

$tmux show-messages [-t target-client] $ tmux suspend-client [-t target-client]

$tmux switch-client [-c target-client] [-t target-session] Formats tmux provides a minimal template language and set of variables to access information about your tmux environment. Formats are specified via the -F flag. You know how template engines, such as mustache, handlebars ERB in ruby, jinja2 in python, twig in PHP, and JSP in Java, allow template variables? Formats are a similar concept. The FORMATS (variables) provided by tmux have expanded greatly since version 1.8. Some of the most commonly used formats as of tmux 2.3 are listed below. See the appendix section on formats for a complete list. Let’s try to output it: Here’s a cool trick; list all panes with the x and y coordinates of the cursor position: Variables are specific to the objects being listed. For instance: Server-wide variables: host, host_short (no domain name), socket_path, start_time and pid. Session-wide variables: session_attached, session_activity, session_created, session_height, session_id, session_name, session_width, session_windows and all server-wide variables. Window variables: window_activity, window_active, window_height, window_id, window_index, window_layout, window_name, window_panes, window_width and all session and server variables. Pane variables: cursor_x, cursor_y, pane_active, pane_current_command, pane_current_path, pane_height, pane_id, pane_index, pane_width, pane_pid and all window, session and server variables. Remember the graphic that showed how servers encapsulated sessions, sessions held windows, windows held panes? That concept plays a role here. If you list-panes, all variables up the ladder, including window, session and server variables are available for the panes being listed. Example: 11. Tips and Tricks Read the tmux manual in style $ man tmux is the command to load up the “man page” for tmux. You can do the same to find instructions for just about any comment; here’s two fun ones:

most(1) is a solid PAGER that drastically improves readability of manual pages by acting as a syntax highlighter.

To get this working, you need to set your PAGER environmental variable to point to the MOST binary. You can test it like this:

If you found you like most, you’ll probably want to make it your default manpage reader. You can do this by setting an environmental variable in your “rc” (Run Commands) for your shell. The location of the file depends on your shell. You can use $echo$SHELL to find it on most shells). In Bash and zsh, these are kept in ~/.bashrc or ~/.zshrc, respectively:

I often reuse my configurations across machines, and some of them may not have most installed, so I will have my scripting only set PAGER if most is found:

Save that to a file, let’s say ~/.dot-config/most.sh.

Then you can source it in via your main rc file.

If you keep that pattern (or something close to it), you’re on your way to a cross-platform, modular dot config. If you need inspiration, you can check my public permissively licensed config at https://github.com/tony/.dot-config. I document it well and welcome you to copy/paste from it, too.

Log tailing

Not tmux specific, but powerful when used in tandem with it, you can run a follow (-f) using tail(1). More modern versions of tail have the -F (capitalized), which checks for file renames and rotation.

On OS X, you can do:

and keep that open in a pane. It’s kind of like a Facebook newsfeed, except for programmers and system administrators.

For monitoring logs, multitail is a terminal friendly solution. It’d be an Inception moment, because you’d be using a log multiplexer in a terminal multiplexer.

File watching

In my never-ending conquest to get software projects working in symphony with code changes, I’ve come to taste test many file watching applications and patterns. To get that perfect feedback look upon files changing, I’ve gradually become the internet’s unofficial connoisseur on them.

What this application does is wait for a file to be updated, then executes a custom command, like restarting a server, rebuilding an application, running tests, linters, and so on. It gives you, as a developer instant feedback in the terminal and is one thing that can trick out a tmux workspace into an IDE-like environment.

I eventually settled on entr(1), which works superbly across Linux distros, BSDs and OS X / macOS.

The trick to make entr work is to pipe a list of files into it to watch.

Let’s search for all .go files in a directory and run tests on file change:

Sometimes, we may want to watch files recursively, and we need to do that in a cross-platform way. We can’t depend on ** existing to grab files recursively. Something more POSIX friendly would be find . -print | grep -i '.*[.]go':

Only run file watcher if entr is installed; let’s wrap in a conditional command -v test:

And have it fallback to go test in the event entr isn’t installed. You’ll thank me when use this command in conjunction with a session manager:

Show a notice message to user to install entr if not installed on the system:

Here’s why you want patterns like that: You can put it into a Makefile and commit it to your project’s VCS, so you and other developers can have access to this reusable command across different UNIX-like systems, with and without that certain program installed.

Note: You may have to convert the indentation within the Makefiles from spaces to tabs.

Let’s see what a Makefile with this looks like:

To run this, do $make watch_test in the same directory as the Makefile. But that was a tad bloated and hard to read. We have a couple tricks at our disposal. One would be to add continuation to the next line with a trailing backslash (\): Another would be to break the command into variables and make subcommands. So, let’s try that: $(MAKE) is used for portability. One reason is recursive calls, such as here. On BSD systems, you may try invoking make via gmake (to call GNU Make specifically). This happened to me, while building PDFs for the book AlgoXY. I had to write a patch to make it properly use $(MAKE) for recursive calls. The $(test) after go test allows passing a shell variable with arguments in it. So, you could do make watch_test test='-i'. For examples of a similar Makefile in action, see the one in my tmuxp project. The project is licensed BSD (permissive), so you can grab code and use it in compliance with the LICENSE.

One more thing, let’s say you’re running a server, like Gin, Iris, or Echo. entr -c likely won’t be restarting the server for you. Try entering the -r flag to send a SIGTERM to the process before restarting it. Combining the current -c flag with the new -r will give you entr -rc:

Session Managers

For those who use tmux regularly to perform repetitive tasks, such as opening the same software project, view the same logs, etc., applications that store your layouts declaratively in a YAML or JSON file help you boot up your session fast.

Teamocil and Tmuxinator are the first ones I tried. By far, the most popular one is tmuxinator. They are both programmed in Ruby. There’s also tmuxomatic, where you can “draw” your tmux sessions in text and have tmuxomatic build the layout.

I sort of have a home team advantage here, as I’m author of tmuxp. I wrote it, already having used teamocil and tmuxinator, but with many more features. For one, it builds on top of libtmux, a library which abstracts tmux server, sessions, windows and panes to build the state of tmux sessions. In addition, it has a naive form of session freezing, support for JSON, more flexible configuration options, and it will even offer to attach sessions that exist, instead of redundantly running script commands against the session if it is already running.

So, in tmuxp, we’ll hollow out a tmuxp config directory with $mkdir ~/.tmuxp then create a YAML file at ~/.tmuxp/test.yaml: gives a session titled 4-pane-split, with one window titled dev window with 4 panes in it. 3 in the home directory; the other is in /var/log and is printing a list of all files ending with .log. To launch it, install tmuxp and load the configuration: If tmuxp isn’t found, there is a troubleshooting entry on fixing your paths in the appendix. More code and examples I’ve dusted off a C++ space shooter and a new go webapp I’ve been playing with. They’re licensed under MIT so, you can use them, copy and paste from them, etc: Both support tmuxp load . within the project directory to load up the project. Make sure to install entr(1) beforehand! tmux-plugins and tpm tmux-plugins and tmux package manager are a suite of tools dedicated to enhancing the experience of tmux users. • tmux-resurrect: Persists tmux environment across system restarts. • tmux-continuum: Continuous saving of tmux environment. Automatic restore when tmux is started. Automatic tmux start when computer is turned on. • tmux-yank: Tmux plugin for copying to system clipboard. Works on OSX, Linux and Cygwin. • tmux-battery: Plug and play battery percentage and icon indicator for Tmux. 12. Cheatsheets These are taken directly from tmux’s manual pages, tabled and organized by hand into sections for convenience. Commands Session Command Action no command Short-cut for new-session attach-session Attach or switch to a session choose-session Put a window into session choice mode has-session Check and report if a session exists on the server kill-session Destroy a given session list-sessions List sessions managed by server lock-session Lock all clients attached to a session new-session Create a new session rename-session Rename a session Window Command Action choose-window Put a window into window choice find-window Search for a pattern in windows kill-window Destroy a given window last-window Select the previously selected link-window Link a window to another list-windows List windows of a session move-window Move a window to another new-window Create a new window next-window Move to the next window in a sesssion previous-window Move to the previous window in session rename-window Rename a window respawn-window Reuse a window in which a command has exited rotate-window Rotate positions of panes in a window select-window Select a window set-window-option Set a window option show-window-options Show window options split-window Splits a pane into two swap-window Swap two windows unlink-window Unlink a window Pane Command Action break-pane Break a pane from an existing into a new window capture-pane Capture the contents of a pane to a buffer display-panes Display an indicator for each visible pane join-pane Split a pane and move an existing one into the new space kill-pane Destroy a given pane last-pane Select the previously selected pane list-panes List panes of a window move-pane Move a pane into a new space pipe-pane Pipe output from a pane to a shell command resize-pane Resize a pane respawn-pane Reuse a pane in which a command has exited select-pane Make a pane the active one in the window swap-pane Swap two panes Keybindings Shortcut Action C-b Send the prefix key (C-b) through to the application. Miscellaneous Shortcut Action C-z Suspend the tmux client. r Force redraw of the attached client. t Show the time. ~ Show previous messages from tmux, if any. f Prompt to search for text in open windows. d Detach the current client. D Choose a client to detach. ? List all key bindings. : Enter the tmux command prompt. Copy/Paste Shortcut Action # List all paste buffers. [ Enter copy mode to copy text or view the history. ] Paste the most recently copied buffer of text. Page Up Enter copy mode and scroll one page up. = Choose which buffer to paste interactively from a list. - Delete the most recently copied buffer of text. Session Shortcut Action $ Rename the current session.
Session Traversal
Shortcut Action
L Switch the attached client back to the last
session.
s Select a new session for the attached client
interactively.

Window

Shortcut Action
c Create a new window.
& Kill the current window.
i Display some information about the current window.
, Rename the current window.
Window Traversal
Shortcut Action
0 to 9 Select windows 0 to 9.
w Choose the current window interactively.
M-n Move to the next window with a bell or activity
marker.
M-p Move to the previous window with a bell or activity
marker.
p Change to the previous window.
n Change to the next window.
l Move to the previously selected window.
' Prompt for a window index to select.
Window Moving
Shortcut Action
. Prompt for an index to move the current window

Pane

Shortcut Action
x Kill the current pane.
q Briefly display pane indexes.
% Split the current pane into two, left and right.
" Split the current pane into two, top and bottom.
Pane Traversal
Shortcut Action
; Move to the previously active pane.
Up, Down Change to the pane above, below, to the left, or to
Left, Right the right of the current pane.
o Select the next pane in the current window.
Pane Moving
Shortcut Action
C-o Rotate the panes in the current window forwards.
M-o Rotate the panes in the current window backwards.
{ Swap the current pane with the previous pane.
} Swap the current pane with the next pane.
! Break the current pane out of the window.
Pane Resizing
Shortcut Action
M-1 to M-5 Arrange panes in one of the five preset layouts:
even-horizontal, even-vertical, main-horizontal,
main-vertical, or tiled.
C-Up, C-Down Resize the current pane in steps of one cell.
C-Left, C-Right
M-Up, M-Down Resize the current pane in steps of five cells.
M-Left, M-Right

Formats

Copy / paste

Variable name Description
buffer_name Name of buffer
buffer_sample Sample of start of buffer
buffer_size Size of the specified buffer in bytes

Clients

Variable name Description
client_activity Integer time client last had activity
client_created Integer time client created
client_control_mode 1 if client is in control mode
client_height Height of client
client_key_table Current key table
client_last_session Name of the client’s last session
client_pid PID of client process
client_prefix 1 if prefix key has been pressed
client_session Name of the client’s session
client_termname Terminal name of client
client_tty Pseudo terminal of client
client_utf8 1 if client supports utf8
client_width Width of client
line Line number in the list

Panes

Variable name Description
alternate_on If pane is in alternate screen
alternate_saved_x Saved cursor X in alternate screen
alternate_saved_y Saved cursor Y in alternate screen
cursor_flag Pane cursor flag
cursor_x Cursor X position in pane
cursor_y Cursor Y position in pane
insert_flag Pane insert flag
mouse_any_flag Pane mouse any flag
mouse_button_flag Pane mouse button flag
mouse_standard_flag Pane mouse standard flag
pane_active 1 if active pane
pane_bottom Bottom of pane
pane_current_command Current command if available
pane_current_path Current path if available
pane_height Height of pane
pane_id Unique pane ID (Alias: #D)
pane_in_mode If pane is in a mode
pane_input_off If input to pane is disabled
pane_index Index of pane (Alias: #P)
pane_left Left of pane
pane_pid PID of first process in pane
pane_right Right of pane
pane_start_command Command pane started with
pane_synchronized If pane is synchronized
pane_tabs Pane tab positions
pane_title Title of pane (Alias: #T)
pane_top Top of pane
pane_tty Pseudo terminal of pane
pane_width Width of pane
scroll_region_lower Bottom of scroll region in pane
scroll_region_upper Top of scroll region in pane
scroll_position Scroll position in copy mode
wrap_flag Pane wrap flag

Sessions

Variable name Description
session_attached Number of clients session is attached to
session_activity Integer time of session last activity
session_created Integer time session created
session_last_attached Integer time session last attached
session_group Number of session group
session_grouped 1 if session in a group
session_height Height of session
session_id Unique session ID
session_many_attached 1 if multiple clients attached
session_name Name of session (Alias: #S)
session_width Width of session
session_windows Number of windows in session

Windows

Variable name Description
history_bytes Number of bytes in window history
history_limit Maximum window history lines
history_size Size of history in bytes
window_activity Integer time of window last activity
window_activity_flag 1 if window has activity
window_active 1 if window active
window_bell_flag 1 if window has bell
window_find_matches Matched data from the find-window
window_flags Window flags (Alias: #F)
window_height Height of window
window_id Unique window ID
window_index Index of window (Alias: #I)
window_last_flag 1 if window is the last used
window_layout Window layout description, ignoring zoomed
window panes
window_name Name of window (Alias: #W)
window_panes Number of panes in window
window_silence_flag 1 if window has silence alert
window_visible_layout Window layout description, respecting
zoomed window panes
window_width Width of window
window_zoomed_flag 1 if window is zoomed

Servers

Variable name Description
host Hostname of local host (alias: #H)
host_short Hostname of local host (no domain name)
(alias: #h)
socket_path Server socket path
start_time Server start time
pid Server PID