Making my tmux life easier

Have you heard of tmux? Do you ache for terminal mutiplexing and persistent shell sessions? If not, you can probably skip this post. Hang tight, I have something more generally palatable in the works. In the meantime, if you want to read up, head to the tmux homepage.

I’ve been enjoying tmux for a while now. I was never a big screens user, but I’d played with it as a basic replacement for nohup on remote sessions. tmux just clicked for me when I sat down to figure it out, though, and I’ve been using it in various ways since.

I’m aware that there’s a method to the madness behind the varying flags used when calling “attach” vs. “new,” for example, but I always get my -s, -t, and -n switched up. I wrote a wrapper to help me out.

Because it only wraps the “attach” and “new” commands, this would generate nested sessions if run within tmux. It’s only really handy if you detach from your sessions regularly instead of just flying between multiple sessions/windows like a pro. I use tmux primarily for setting up remote connections and running on remote servers, so I drop back to Terminal frequently and jump back to sessions as needed.

When sourced in your .bash_profile or .zshrc, it gives you a tm command that you can run with one or two arguments. The first argument is always a session name, the second can specify a window. If the session name you provide matches an existing session (partial names work), you’ll be connected to it, and optionally to a specific window in the session if you supply that argument.

The window name can be partial, too. So if I have a session named “jekyll” and a window called “dev,” I can connect to that window just by running tm jek dev, or just tm j if there are no other sessions starting with “j” and “dev” was my last-used window. If multiple sessions or windows match your partial, the first one alphabetically will be selected.

If no matches are found for the session name, a new session will be created and attached. The second argument can be used to name the first window upon connection.

Here’s the script, do with it what you will.

tmux.bashraw
# Brett Terpstra 2014
# <http://brettterpstra.com>
#
# tmux wrapper
# 	tm session-name [window-name]
# Names can be partial from the beginning and first match will connect.
# If no match is found a new session will be created.
# If there's a second argument, it will be used to attach directly to a
# window in the session, or to name the first window in a new session.
tm() {
	local attach window
	if [ -n $1 ]; then
		attach=""

		tmux has-session -t $1 > /dev/null
		if [ $? -eq 0 ]; then
			attach=$1
			shift
		else
			for session in `tmux ls|awk -F ":" '{ print $1 }'`;do
				if [[ $session =~ ^$1  ]]; then
					echo "Matched session: $session"
					attach=$session
					shift
					break
				fi
			done
		fi

		if [[ $attach != "" ]]; then
			if [ $# -eq 1 ]; then
				for win in `tmux list-windows -t $attach|sed -E 's/^[0-9]+: //'|sed -E 's/[*-].*//'`;do
					if [[ $win =~ ^$1 ]]; then
						echo "Matched window: $window"
						window=$win
						break
					fi
				done

				tmux attach -t $attach:$window
			else
				tmux attach -t $attach
			fi
		else
			if [ $# -gt 1 ]; then
				attach=$1
				shift
				tmux new -s $attach -n $1
			else
				echo "Attempting to create $1"
				tmux new -s $1
			fi
		fi
	else
		tmux new
	fi
}

Just for fun

Here’s a quick snippet you can use in your bash_profile to display a “session:window” banner when you connect to a new window. It uses Figlet, but you can do whatever you want with the $sessionname and $winname variables.

# print a banner for the current window name within tmux
tm-win-banner() {
  local winname sessionname
  if [[ -n $TMUX ]]; then
    sessionname=`tmux list-sessions | grep attached | awk -F: '{print $1}'`
    winname=`tmux list-windows | grep --color=never -E '^\d+: (.*)\*'| awk '{ print $2 }' | tr -d '*'`
    figlet -w `tput cols` -f graffiti "$sessionname:$winname"
  fi
}

When run, this gives me:

You can also split the session and window names up and use them in a PROMPT_COMMAND, but if you’re in tmux you already have a status bar. If you use iTerm 2’s tmux integration, all tabs and windows share the same session, so it’s ultimately kind of pointless. Whatever.

tm-session() {
  local sessionname
  if [[ -n $TMUX ]]; then
    sessionname=`tmux list-sessions | grep attached | awk -F: '{print $1}'`
    echo -n $sessionname
  fi
}

tm-window() {
  local winname
  if [[ -n $TMUX ]]; then
    winname=`tmux list-windows | grep --color=never -E '^\d+: (.*)\*'| awk '{ print $2 }' | tr -d '*'`
    echo -n $winname
  fi
}

Ryan Irelan has produced a series of shell trick videos based on BrettTerpstra.com posts. Readers can get 10% off using the coupon code TERPSTRA.

Brett Terpstra

Brett is a writer and developer living in Minnesota, USA. You can follow him as ttscoff on Twitter, GitHub, and Mastodon. Keep up with this blog by subscribing in your favorite news reader.

This content is supported by readers like you.