This note synthetize my tmux setup. It may look rudimentary but it does the job for my personal use.

Tmux configuration file and zsh/bashrc :

The complete configuration is here and I’ll dig into each parts separately on sub paragraphs.

.tmux.conf file :

set -g mouse
set -g history-limit 50000
#Ctrl-b+e now prompt for VAR=value to be propagated through every windows
bind-key e command-prompt -p "tmux_export VAR=value" "run-shell 'tmux send-keys \"tmux_export %%\" C-m'"
 
# List of plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-logging'
 
 
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '~/.tmux/plugins/tpm/tpm'

.zshrc ; tmux part :

# Ensure Tmux is not already started as active to avoid recursive tmux instantiation and nesting.
if [[ ! "$TERM" =~ screen ]] && [[ ! "$TERM" =~ tmux ]] && [ -z "$TMUX" ] ; then
        tmux new-session -s default -n "shell" -d #Create a new-session named default with a window named "shell"
        tmux split-session -h #Split the active window ("shell")
        tmux new-window -t default:9 -n "openvpn" -d #Create a new window attached to default session as 1 named "openvpn HTB". -d is given to attach after, otherwise it will fail
        tmux select-window -t default #Set active window to default
        tmux -2 attach-session -t default #Start tmux with the default session attached
fi
 
#Populate a variable across all windows in a tmux session.
function tmux_export() {
  if [[ -z "$TMUX" ]]; then
    echo "Error: Not inside tmux" >&2
    return 1
  fi
 
  if [[ "$1" =~ '^([a-zA-Z_][a-zA-Z0-9_]*)=(.*)' ]]; then
    local varname=${match[1]}
    local varvalue=${match[2]}
    export $varname="$varvalue"
 
    local session=$(tmux display-message -p '#S')
    local syncfile="$HOME/.tmux_env_sync"
 
    if [[ -f $syncfile ]]; then
      grep -v "^export $varname=" "$syncfile" > "$syncfile.tmp" || true
      mv "$syncfile.tmp" "$syncfile"
    fi
    echo "export $varname='$varvalue'" >> "$syncfile"
 
    tmux set-environment -t "$session" "$varname" "$varvalue"
 
    local current_pane=$(tmux display-message -p '#{pane_id}')
    local panes=(${(f)"$(tmux list-panes -t "$session" -F '#{pane_id}')"})
    for pane in $panes; do
      if [[ "$pane" != "$current_pane" ]]; then
        tmux send-keys -t "$pane" "source $syncfile" C-m
      fi
    done
  else
    echo "Usage: tmux_export VAR=value" >&2
    return 1
  fi
}
 
#Auto populate on new window in tmux
if [[ -n "$TMUX" ]]; then
  local syncfile="$HOME/.tmux_env_sync"
  if [[ -f $syncfile ]]; then
    source "$syncfile"
  fi
fi

Start Tmux on terminal open

Since I’ve been using tmux extensively while working I’ve looked up on automatically opening tmux on shell startup.

# Ensure Tmux is not already started as active to avoid recursive tmux instantiation and nesting.
if [[ ! "$TERM" =~ screen ]] && [[ ! "$TERM" =~ tmux ]] && [ -z "$TMUX" ] ; then
        tmux new-session -s default -n "shell" -d #Create a new-session named default with a window named "shell"
        tmux split-session -h #Split the active window ("shell")
        tmux new-window -t default:9 -n "openvpn" -d #Create a new window attached to default session as 1 named "openvpn HTB". -d is given to attach after, otherwise it will fail
        tmux select-window -t default #Set active window to default
        tmux -2 attach-session -t default #Start tmux with the default session attached
fi

Spread environment variables

Since I’ll be keeping some variable across all my tmux panes like IP addresses for scope etc… everything is stored in a simple .tmux_env_sync file.

To achieve that I setup an “export” function that can be trigger with CTRL+B+E (see tmux.conf). The idea is simply to add variable to my sync file and then propagate an event through all panes to source it again.

#Populate a variable across all windows in a tmux session.
function tmux_export() {
  if [[ -z "$TMUX" ]]; then
    echo "Error: Not inside tmux" >&2
    return 1
  fi
 
  if [[ "$1" =~ '^([a-zA-Z_][a-zA-Z0-9_]*)=(.*)' ]]; then
    local varname=${match[1]}
    local varvalue=${match[2]}
    export $varname="$varvalue"
 
    local session=$(tmux display-message -p '#S')
    local syncfile="$HOME/.tmux_env_sync"
 
#Make sure the variable isn't already assigned, otherwise remove it and appends the new one.
    if [[ -f $syncfile ]]; then
      grep -v "^export $varname=" "$syncfile" > "$syncfile.tmp" || true
      mv "$syncfile.tmp" "$syncfile"
    fi
    echo "export $varname='$varvalue'" >> "$syncfile"
 
    tmux set-environment -t "$session" "$varname" "$varvalue"
 
    local current_pane=$(tmux display-message -p '#{pane_id}')
    local panes=(${(f)"$(tmux list-panes -t "$session" -F '#{pane_id}')"})
    for pane in $panes; do
      if [[ "$pane" != "$current_pane" ]]; then
        tmux send-keys -t "$pane" "source $syncfile" C-m
      fi
    done
  else
    echo "Usage: tmux_export VAR=value" >&2
    return 1
  fi
}
 
#Auto populate on new window in tmux
if [[ -n "$TMUX" ]]; then
  local syncfile="$HOME/.tmux_env_sync"
  if [[ -f $syncfile ]]; then
    source "$syncfile"
  fi
fi

Log commands

History is cool and all but I needed to store that somewhere properly. Documentation & Reporting logging section was very useful. Use :

  • Alt + C to clear history
  • Alt + P to take a text screenshot of the pane
  • Alt + Shift + P to screenshot the window (multiple panes)

I’ve changed the formatting to only keep day month year so that every logging is under the same file per day. Even if you lose some of the precision it’s a comfort choice that feels better while working.