Christopher Peterson

January 26, 2020

Tmux: easily change the default path for new windows



Tmux is a wonderful terminal multiplexer, a little newer and a little more fun than the GNU Screen that you may be used to. This article outlines a drop-in solution for changing the default path for new Tmux windows from within a Tmux session.

In Tmux the directory where you begin your session becomes the default path for new windows. Sometimes you night want to change this while still inside the session.

Before version 1.9

Versions of Tmux prior to 1.9 offered the ability to change this via setting a simple session option:

tmux set-option default-path /some/new/path

After 1.9

But after 1.9, although you can pass any path to the new-window command, the only remaining straightforward way to just change the default path for new windows in a session overall is to detach and reattach the session in the new directory.

That’s too much of an interruption for me!

Some people juggle environment variables and send them to new-window to get around this, but I wanted less fuss in my tmux.conf so I wrote an external script to do all the work.

Essentially, the move is to make a new detached session and reattach the original session in the new directory inside of that session. Yes, this is awkward, but it’s not my fault! 🤷

General Solution

This script!

#!/usr/bin/env bash
# [Christopher Peterson](https://cspeterson.net)

# Details of this script's function are in the help output

# Establish random session name
chars='123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
tmp_session=$(
  for i in {1..8}; do
    echo -n "${chars:RANDOM%${#chars}:1}"
  done
)

######
# Args
######
read -r -d '' helpoutput <<EOF
  Usage:
    ${0} [ARGS]

      Changes the default path for new windows from *within* a Tmux session.
      (Works with versions both before 1.9 and after)

  Positional arguments:
    [ARGS]
        A new default path in which Tmux should open new windows.

  Example
      ${0} /new/default/path

  Dependencies:
    * Bash
    * Tmux
    * bc
    * grep
EOF

fail_help() {
  echo "${helpoutput}"
  exit 1
}

if [ $# -ne 1 ]; then
  fail_help
fi

######
# Deps
######
command -v bash >/dev/null || fail_help
command -v bc >/dev/null || fail_help
command -v grep >/dev/null || fail_help
command -v tmux >/dev/null || fail_help
command -v wc >/dev/null || fail_help

######
# Traps
######
trap early_exit SIGINT
early_exit() {
  tmux kill-session -t "${tmp_session}"
  exit $?
}

######
# Main
######
newdir="${1}"
if ! [ -d "${newdir}" ]; then
  exit 1
fi

session_client_count () {
  sess="${1}"
  count=$(tmux list-clients -t "${sess}" | wc -l)
  echo "${count}"
}

if [ -z "${TMUX}" ]; then
  exit 1
fi
vers=$(tmux -V | grep -Po '[0-9\.]*')

curr_session=$(tmux display -p '#S')

# This is dumb but stay with me - Tmux doesn't use semver
if (( $(echo "${vers} < 1.9" | bc -l) )); then
  tmux set-option default-path "${newdir}"
else
  # In order to change the default working directory in Tmux >=1.9 from
  # *within* the same session, we'll need to jump through some hoops.
  # So! Make a new session and inside that session, attach the *first* session
  # in a manner that alters the default path. Then, kill the second session and
  # you're back where you started, but with a new working dir 👍
  tmux new-session -d -t "${tmp_session}"
  tmux send-keys -t "${tmp_session}" 'unset TMUX' Enter
  client_count=$(session_client_count "${curr_session}")
  tmux send-keys -t "${tmp_session}" "tmux attach-session -t \"${curr_session}\" -c \"${newdir}\"" Enter
  start_count="${client_count}"
  while (( client_count <= start_count )); do
    client_count=$(session_client_count "${curr_session}")
  done
  tmux kill-session -t "${tmp_session}"
fi

Use like:

tmux-chdir /some/new/directory

In case of any updates to this script, you can always check the live version in my dotfiles: