Zooming tmux panes

The recently released tmux 1.8 includes a new feature, zoomed panes, that allows temporarily expanding a pane to the full size of the tmux window to see more of its contents.

In the man page for tmux(1), the feature is described as follows, under the details for the resize-pane command:

With -Z, the active pane is toggled between zoomed (occupying the
whole of the window) and unzoomed (its normal position in the
layout).

This command is bound to <prefix> z by default; for most users, this will be Ctrl-a z. The effect can be observed by pressing this key sequence in any window with at least two panes, to toggle the zoomed state for the active pane:

Toggle pane zoom state

Note the Z suffix that appears after the window title in the status bar while the pane is zoomed.

For most users, the new feature should mean that any custom maximize/minimize style bindings they may be using are no longer needed. This works particularly smoothly given that the new release also includes support for reflowing text when panes and windows are resized, something GNU Screen has supported for some time.

Be sure to take a look at some of the other changes in the newest release of tmux. If you’re using a DPKG or RPM based packaging system, you might like to build it from source and install it with checkinstall(8).

Sync tmux panes

If you have a Tmux window divided into panes, you can use the synchronize-panes window option to send each pane the same keyboard input simultaneously:

Synchronize panes demo

You can do this by switching to the appropriate window, typing your Tmux prefix (commonly Ctrl-B or Ctrl-A) and then a colon to bring up a Tmux command line, and typing:

:setw synchronize-panes

You can optionally add on or off to specify which state you want; otherwise the option is simply toggled. This option is specific to one window, so it won’t change the way your other sessions or windows operate. When you’re done, toggle it off again by repeating the command.

This is an easy way to run interactive commands on multiple machines, perhaps to compare their speed or output, or if they have a similar setup a quick and dirty way to perform the same administrative tasks in parallel. It’s generally better practice to use Capistrano or Puppet for the latter.

Tmux environment variables

The user configuration file for the tmux terminal multiplexer, .tmux.conf, supports defining and using environment variables in the configuration, with the same syntax as most shell script languages:

TERM=screen-256color
set-option -g default-terminal $TERM

This can be useful for any case in which it may be desirable to customise the shell environment when inside tmux, beyond setting variables like default-terminal. However, if you repeat yourself in places in your configuration file, it can also be handy to use them as named constants. An example could be establishing colour schemes:

TMUX_COLOUR_BORDER="colour237"
TMUX_COLOUR_ACTIVE="colour231"
TMUX_COLOUR_INACTIVE="colour16"

set-window-option -g window-status-activity-bg $TMUX_COLOUR_BORDER
set-window-option -g window-status-activity-fg $TMUX_COLOUR_ACTIVE
set-window-option -g window-status-current-format "#[fg=$TMUX_COLOUR_ACTIVE]#I:#W#F"
set-window-option -g window-status-format "#[fg=$TMUX_COLOUR_INACTIVE]#I:#W#F"

The explicit commands to work with environment variables in .tmux.conf are update-environment, set-environment, and show-environment, and are featured in the manual.

Reloading tmux config

If you have made changes to your tmux configuration file in the ~/.tmux.conf file, it shouldn’t be necessary to start the server up again from scratch with kill-server. Instead, you can prompt the current tmux session to reload the configuration with the source-file command.

This can be done either from within tmux, by pressing Ctrl+B and then : to bring up a command prompt, and typing:

:source-file ~/.tmux.conf

Or simply from a shell:

$ tmux source-file ~/.tmux.conf

This should apply your changes to the running tmux server without affecting the sessions or windows within them.

Vi mode in tmux

tmux offers a set of vi-like bindings for navigating a buffer in a window. These allow you to not only navigate through the buffer beyond what your screen is currently showing, but also to search all the output generated thus far, and to select and copy text that can be pasted in any other window in the tmux session.

You can enable this as a default setting in .tmux.conf with the following:

set-window-option -g mode-keys vi

You can confirm this is working by pressing Ctrl+B and then : in a tmux session to bring up the command line, and typing:

list-keys -t vi-copy

This will bring up a complete list of the vi-like functionality available to you in this mode.

With this done, within a tmux instance, pressing Ctrl+B and then [ will enter copy mode, allowing you to copy text or view the history of the buffer, including searching with / and ?. Most of the basic vi movements work, including screenwise vertical movement commands like Ctrl+F and Ctrl+B. You can leave this mode just by pressing Enter, or you can start a selection by pressing Space on a character, moving to another, and then pressing Enter. If you have text copied like this you can paste it into any tmux window in that session by pressing Ctrl+B and then ].

If you don’t mind artifically introducing a few Vim-only features to the vi mode, you can set things up so that v starts a selection and y finishes it in the same way that Space and Enter do, more like Vim:

bind-key -t vi-copy 'v' begin-selection
bind-key -t vi-copy 'y' copy-selection

A possible snag to remember here is that for most older versions, tmux selections don’t include the character under the cursor, whereas Vim visual selections do include it unless you change the exclusive option from its default of no. This has been fixed in more recent builds of tmux, however, so if you find it as jarring as I did and your package manager has a version of tmux older than 1.5, you may like to consider upgrading or compiling tmux locally.

Even if you’re using a terminal emulator in a GUI environment, if you get good at using this you’ll find it’s much faster and more precise than clicking and dragging to select text to copy and paste it. It keeps you from having to move to the mouse, and additionally eliminates the problem of copying whole lines split into more than one panes.

Note that all of the above assumes that your prefix is the default of Ctrl+B, which many tmux users, myself included, seem to prefer to change to the old GNU Screen prefix key of Ctrl+A.

Automatic tmux titles

If you’re using tmux as a terminal multiplexer and keeping one window open per host, you might be manually renaming each window to feature the relevant hostname. This is a little annoying to do if you’re dealing with a lot of hosts, so it’s worthwhile to automate it.

In the tmux manual, the following escape code incantation is given to update the window title from within the terminal:

$ printf '\033kWINDOW_NAME\033\\'

In much the same way that you can update the title of an xterm-compatible terminal emulator with control codes as part of the $PS1 variable defining the prompt, you can update the title of a tmux window to the current hostname (or any other relevant text) automatically by prefixing this call to the $PROMPT_COMMAND. This is best done in your .bashrc. The below code assumes you are using either screen or screen-256color as your $TERM string in your .tmux.conf:

case "$TERM" in
    screen*)
        PROMPT_COMMAND="printf '\033k$(hostname)\033\\';"${PROMPT_COMMAND}
        ;;
esac

After logging out and in again, this will update the title of the window to the hostname of the current machine just before the prompt is presented, saving you the trouble of updating the window title if like myself you never use it for anything besides the machine’s hostname.

Watching with tmux

watch is one of those Unix tools which does something very simple, but combined with other tools has a myriad of uses. While there are a few useful features or switches for watch, its central concept is simple; it runs something for you repeatedly, and shows the output on the screen.

The reason this becomes so useful in a system administration context is that when used with a terminal multiplexer, watch can be used to track the progress of any particular task, or to monitor system resources, as you work and change things. Some examples of simple but useful monitoring tasks are:

  • Load averagewatch uptime
  • Disk spacewatch df -h
  • Process countwatch 'ps -ef | wc -l'
  • Memory usagewatch free -m
  • Size of a volatile filewatch du -sh filename.sh

Of course, it’s not a terribly good use of an administrator or developer’s time to just sit there and watch these change, particularly if you want to make changes to the system or application and see how they affect the results of your monitoring. This is where a terminal multiplexer like tmux comes in handy, for putting instances of watch and other more complex monitoring tools like htop or tload into independent panes of a terminal window so you can work as you watch them.

Monitoring tasks running in tmux

Monitoring tasks running in tmux

You can set these windows up using the usual key combinations, but if you have a long string of text or a known command that you want to start running in another window, it’s often easier to call the relevant tmux commands directly from the shell:

$ watch uptime
$ tmux split-window -dh "!!"

This will split the window into two parts, and run watch uptime in the new one, while leaving your cursor in the original window.

If you find yourself doing this often, you could make it into a shell function in your .bashrc or similar:

function tmw {
    tmux split-window -dh "$*"
}

You can then quickly run things like the following, as a kind of general method to background a monitoring or long-running task quickly:

$ tmw watch uptime
$ tmw htop
$ tmw rsync -arvz source::mnt/location /home/tom/destination

Thanks to user WishCow for pointing out an error in the comments.