> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/tmux/tmux/llms.txt
> Use this file to discover all available pages before exploring further.

# Scripting tmux

> Using if-shell, run-shell, display-message, and source-file for tmux automation

## Introduction to tmux Scripting

tmux provides powerful scripting capabilities that allow you to:

* Automate session and window creation
* Execute conditional logic
* Run shell commands in the background
* Display formatted information
* Load and organize configuration files

<Note>
  All tmux commands can be scripted, whether from configuration files, shell scripts, or key bindings.
</Note>

## The if-shell Command

The `if-shell` command executes tmux commands conditionally based on shell command results.

### Basic Syntax

```bash theme={null}
if-shell [-bF] [-t target-pane] shell-command tmux-command [else-command]
```

### Simple Conditional

```bash theme={null}
# If shell command succeeds, run tmux command
if-shell "test -f ~/.tmux.local.conf" "source ~/.tmux.local.conf"

# With else clause
if-shell "[ -d /opt/local ]" \
  "set-option -g default-command /opt/local/bin/bash" \
  "set-option -g default-command /bin/bash"
```

### Background Execution

```bash theme={null}
# Run shell command in background with -b
if-shell -b "sleep 5 && echo done" "display 'Command completed'"

# Without -b, subsequent commands wait for shell command to finish
if-shell "curl -s https://api.example.com" "display 'API available'"
```

### Format Expansion

Use `-F` to treat the shell command as a format string instead of executing it:

```bash theme={null}
# Check if format evaluates to non-empty and non-zero
if-shell -F '#{window_zoomed_flag}' \
  'set-option status-style bg=red' \
  'set-option status-style bg=green'

# Check session count
if-shell -F '#{>:#{session_windows},5}' \
  'display "Too many windows!"'

# String comparison
if-shell -F '#{==:#{host},myserver}' \
  'set-option -g status-left "[SERVER] "'
```

### Real-World Examples

<Tabs>
  <Tab title="Conditional Config Loading">
    ```bash theme={null}
    # Load different configs based on hostname
    if-shell '[ "$(hostname)" = "workstation" ]' \
      'source ~/.tmux.work.conf' \
      'source ~/.tmux.home.conf'

    # Load OS-specific config
    if-shell 'uname | grep -q Darwin' \
      'source ~/.tmux.macos.conf'

    if-shell 'uname | grep -q Linux' \
      'source ~/.tmux.linux.conf'
    ```
  </Tab>

  <Tab title="Feature Detection">
    ```bash theme={null}
    # Enable true color if supported
    if-shell '[[ $COLORTERM = truecolor ]]' \
      'set-option -ga terminal-overrides ",*256col*:Tc"'

    # Check tmux version
    if-shell '[ "$(tmux -V | cut -d" " -f2)" -ge "3.2" ]' \
      'set-option -g extended-keys on'

    # Check for clipboard command
    if-shell 'command -v xclip' \
      'set-option -g @clipboard xclip' \
      'set-option -g @clipboard pbcopy'
    ```
  </Tab>

  <Tab title="Dynamic Status">
    ```bash theme={null}
    # Show different status based on session
    if-shell -F '#{==:#{session_name},work}' \
      'set-option -g status-style bg=blue' \
      'set-option -g status-style bg=green'

    # Alert if too many panes
    if-shell -F '#{>:#{window_panes},4}' \
      'set-option -w window-status-style bg=red'
    ```
  </Tab>
</Tabs>

### Nested if-shell

You can nest `if-shell` commands:

```bash theme={null}
if-shell 'tmux run "true"' \
  'if-shell "test -f ~/.tmux.conf" "set -s @done yes"'
```

<Warning>
  Be careful with nested if-shell commands as they can become difficult to read and debug. Consider using format-based conditionals with `-F` instead.
</Warning>

## The run-shell Command

The `run-shell` command executes shell commands in the background without creating a window.

### Basic Syntax

```bash theme={null}
run-shell [-bCE] [-c start-directory] [-d delay] [-t target-pane] shell-command
```

### Simple Execution

```bash theme={null}
# Run command in background
run-shell "sleep 5 && tmux display 'Done'"

# Run immediately (don't wait for prompt)
run-shell -b "curl -s https://api.example.com/notify"
```

### Output Display

By default, command output is shown in view mode:

```bash theme={null}
# Output displayed in current pane
run-shell "ls -la"

# Output displayed in specific pane
run-shell -t %2 "df -h"

# Redirect stderr to stdout
run-shell -E "command-that-may-error 2>&1"
```

### Running tmux Commands

Use `-C` to run tmux commands instead of shell commands:

```bash theme={null}
# Run tmux command
run-shell -C "display-message 'Hello from run-shell'"

# Chain tmux commands
run-shell -C "split-window ; send-keys 'htop' Enter"
```

### Delayed Execution

```bash theme={null}
# Wait before executing
run-shell -d 5 "tmux display 'Delayed message'"

# Useful for startup sequences
run-shell -d 1 "tmux select-window -t :0"
run-shell -d 2 "tmux split-window -h"
run-shell -d 3 "tmux send-keys 'vim' Enter"
```

### Working Directory

```bash theme={null}
# Run in specific directory
run-shell -c /var/log "tail -n 20 syslog | tmux load-buffer -"

# Use current pane directory
run-shell -c '#{pane_current_path}' "git status"
```

### Practical Examples

<Accordion title="Background Tasks">
  ```bash theme={null}
  # Update status bar periodically
  bind-key U run-shell -b \
    'while true; do \
       tmux set-option -g status-right "$(date)"; \
       sleep 60; \
     done'

  # Fetch and display data
  bind-key W run-shell -b \
    'weather=$(curl -s "wttr.in?format=%c+%t"); \
     tmux set-option -g @weather "$weather"'
  ```
</Accordion>

<Accordion title="Error Logging">
  ```bash theme={null}
  # Log errors to file
  set-hook -g command-error \
    'run-shell "echo \'Command failed\' >> /tmp/tmux-errors.log"'

  # Display and log
  set-hook -g command-error \
    'run-shell -E "echo \'Error: #{error}\' | tee -a ~/tmux.log"'
  ```
</Accordion>

<Accordion title="Session Snapshots">
  ```bash theme={null}
  # Save session layout
  bind-key S run-shell \
    'tmux list-windows -F "#{window_index}:#{window_name}" > ~/.tmux-snapshot'

  # Capture all panes
  bind-key C run-shell \
    'for pane in $(tmux list-panes -F "#{pane_id}"); do \
       tmux capture-pane -p -t $pane > ~/pane-${pane}.txt; \
     done'
  ```
</Accordion>

## The display-message Command

The `display-message` command shows messages and evaluates formats.

### Basic Display

```bash theme={null}
# Show message in status line
tmux display-message "Hello, tmux!"
tmux display "Simpler syntax"

# Show for specific duration (milliseconds)
tmux display -d 5000 "This message stays for 5 seconds"

# Show until keypress
tmux display -d 0 "Press any key to continue"

# Print to stdout instead
tmux display -p "Output to terminal"
```

### Format Expansion

Display formatted information:

```bash theme={null}
# Show current session info
tmux display "Session: #{session_name}, Windows: #{session_windows}"

# Show pane info  
tmux display "Pane #{pane_index}: #{pane_current_command}"

# Multiple variables
tmux display "#{session_name}:#{window_index}.#{pane_index}"

# Print format to stdout
tmux display -p '#{pane_current_path}'
```

### Script Integration

<Tabs>
  <Tab title="Get Values">
    ```bash theme={null}
    # Get current path
    path=$(tmux display -p '#{pane_current_path}')
    cd "$path"

    # Get session name
    session=$(tmux display -p '#{session_name}')
    echo "Current session: $session"

    # Get window list
    windows=$(tmux display -p '#{session_windows}')
    ```
  </Tab>

  <Tab title="Conditional Display">
    ```bash theme={null}
    # Show only if condition met
    tmux display -p \
      '#{?window_zoomed_flag,ZOOMED,normal}'

    # Complex conditional
    tmux display -p \
      '#{?#{>:#{window_panes},1},multi-pane,single-pane}'
    ```
  </Tab>

  <Tab title="Formatted Output">
    ```bash theme={null}
    # List all sessions with details
    tmux display -p \
      '#{T:session_name}: #{session_windows} windows, #{session_attached} clients'

    # Window list
    for i in $(seq 0 9); do
      tmux display -p -t :$i \
        'Window #{window_index}: #{window_name}' 2>/dev/null
    done
    ```
  </Tab>
</Tabs>

### Verbose Mode and Debugging

```bash theme={null}
# Show format parsing details
tmux display -v "Session: #{session_name}"

# List all format variables
tmux display -a

# Literal output (no format expansion)
tmux display -l "Literal: #{not_a_variable}"
```

### Forwarding Input

```bash theme={null}
# Forward stdin to empty pane
tmux display-message -I -t %3
# Now type or pipe input
echo "hello" | tmux display-message -I -t %3
```

## The source-file Command

The `source-file` command loads and executes tmux commands from files.

### Basic Usage

```bash theme={null}
# Load configuration file
tmux source-file ~/.tmux.conf
tmux source ~/.tmux.conf  # Short form

# Load multiple files
tmux source-file ~/.tmux.conf ~/.tmux.local.conf

# Silent loading (no error if file doesn't exist)
tmux source-file -q ~/.tmux.optional.conf
```

### Format Expansion

```bash theme={null}
# Expand format in file path
tmux source-file -F "~/.tmux/#{host}.conf"

# Load config based on session
tmux source-file -F "~/.tmux/#{session_name}.conf"
```

### Parse Without Executing

```bash theme={null}
# Check syntax without running commands
tmux source-file -n ~/.tmux.conf

# Show parsed commands
tmux source-file -nv ~/.tmux.conf
```

### Organized Configuration

Split configuration into multiple files:

```bash theme={null}
# ~/.tmux.conf
source-file ~/.tmux/options.conf
source-file ~/.tmux/bindings.conf
source-file ~/.tmux/status.conf
source-file -q ~/.tmux/local.conf
```

<Accordion title="Example: options.conf">
  ```bash theme={null}
  # General options
  set-option -g default-terminal "screen-256color"
  set-option -g history-limit 10000
  set-option -g mouse on
  set-option -g base-index 1
  set-option -w pane-base-index 1
  ```
</Accordion>

<Accordion title="Example: bindings.conf">
  ```bash theme={null}
  # Key bindings
  unbind C-b
  set-option -g prefix C-a
  bind-key C-a send-prefix

  bind | split-window -h
  bind - split-window -v

  bind r source-file ~/.tmux.conf \; display "Reloaded!"
  ```
</Accordion>

<Accordion title="Example: status.conf">
  ```bash theme={null}
  # Status line configuration
  set-option -g status-position bottom
  set-option -g status-style bg=black,fg=white
  set-option -g status-left "[#S] "
  set-option -g status-right "%H:%M %d-%b-%y"
  ```
</Accordion>

### Conditional Loading

```bash theme={null}
# Load host-specific config
if-shell '[ -f ~/.tmux.$(hostname).conf ]' \
  'source-file ~/.tmux.$(hostname).conf'

# Load based on tmux version
if-shell '[ "$(tmux -V | cut -d" " -f2)" -ge "3.0" ]' \
  'source-file ~/.tmux/tmux3.conf' \
  'source-file ~/.tmux/tmux2.conf'
```

## Advanced Scripting Patterns

### Command Sequences

Chain multiple commands:

```bash theme={null}
# Semicolon separator
tmux new-window ; split-window -h ; split-window -v

# Using \; in shell
tmux new-window \; split-window -h \; split-window -v

# With bind-key
bind-key S split-window -h \; split-window -v

# Error handling (stop on error)
tmux new-window ; invalid-command ; display "This won't run"
```

### Using Formats in Scripts

```bash theme={null}
# Get information for scripting
pane_path=$(tmux display -p '#{pane_current_path}')
pane_cmd=$(tmux display -p '#{pane_current_command}')
session=$(tmux display -p '#{session_name}')

# Conditional based on format
if tmux display -p '#{window_zoomed_flag}' | grep -q 1; then
  echo "Window is zoomed"
fi

# Iterate over panes
for pane in $(tmux list-panes -F '#{pane_id}'); do
  cmd=$(tmux display -p -t $pane '#{pane_current_command}')
  echo "Pane $pane running: $cmd"
done
```

### Session Management Scripts

<Steps>
  ### Session Creation Script

  ```bash theme={null}
  #!/bin/bash
  # create-dev-session.sh

  SESSION="dev"

  # Check if session exists
  tmux has-session -t $SESSION 2>/dev/null

  if [ $? != 0 ]; then
    # Create new session
    tmux new-session -d -s $SESSION -n editor
    
    # Setup editor window
    tmux send-keys -t $SESSION:editor 'cd ~/projects' C-m
    tmux send-keys -t $SESSION:editor 'vim' C-m
    
    # Create console window
    tmux new-window -t $SESSION -n console
    tmux split-window -t $SESSION:console -h
    
    # Create server window
    tmux new-window -t $SESSION -n server
    tmux send-keys -t $SESSION:server 'npm start' C-m
    
    # Select first window
    tmux select-window -t $SESSION:editor
  fi

  # Attach to session
  tmux attach-session -t $SESSION
  ```

  ### Layout Save/Restore

  ```bash theme={null}
  # Save layout
  tmux_save_layout() {
    local file="$HOME/.tmux-layout-$(date +%s)"
    
    tmux list-windows -F \
      "#{window_index}:#{window_name}:#{window_layout}" > "$file"
    
    tmux list-panes -F \
      "#{window_index}.#{pane_index}:#{pane_current_path}:#{pane_current_command}" \
      >> "$file"
    
    echo "Layout saved to $file"
  }

  # Restore layout
  tmux_restore_layout() {
    local file="$1"
    
    # Read window layouts
    while IFS=: read -r idx name layout; do
      tmux new-window -n "$name"
      tmux select-layout -t :$idx "$layout"
    done < <(grep -v '\.' "$file")
  }
  ```
</Steps>

### Error Handling

```bash theme={null}
# Capture command errors
if ! tmux select-window -t :99 2>/dev/null; then
  echo "Window 99 doesn't exist"
  tmux new-window -t :99
fi

# Use hooks for error logging
set-hook -g command-error \
  'run-shell "echo #{error} >> ~/.tmux-errors.log"'

# Check exit status
tmux if-shell "test $? -eq 0" \
  "display 'Success'" \
  "display 'Failed'"
```

## Environment Variables in Scripts

tmux provides useful environment variables:

```bash theme={null}
# Available in panes
echo $TMUX              # Socket and session info
echo $TMUX_PANE         # Current pane ID
echo $TERM              # Terminal type

# Use in scripts
if [ -n "$TMUX" ]; then
  echo "Running inside tmux"
  pane_id="$TMUX_PANE"
fi
```

### Setting Environment Variables

```bash theme={null}
# Set for session
tmux set-environment -t mysession MYVAR value

# Global environment
tmux set-environment -g GLOBALVAR value

# Hidden variable (not passed to new processes)
tmux set-environment -h SECRETVAR value

# Use in formats
tmux display -p '#{MYVAR}'
```

## Complete Scripting Example

A comprehensive project setup script:

```bash theme={null}
#!/bin/bash
# project-session.sh - Create a development session

PROJECT_NAME="${1:-myproject}"
PROJECT_DIR="${2:-$HOME/projects/$PROJECT_NAME}"
SESSION="$PROJECT_NAME"

# Check if session already exists
if tmux has-session -t "$SESSION" 2>/dev/null; then
  echo "Session $SESSION already exists. Attaching..."
  tmux attach-session -t "$SESSION"
  exit 0
fi

# Create session
tmux new-session -d -s "$SESSION" -n editor -c "$PROJECT_DIR"

# Setup editor window
tmux send-keys -t "$SESSION:editor" 'vim .' C-m

# Create git window
tmux new-window -t "$SESSION" -n git -c "$PROJECT_DIR"
tmux split-window -t "$SESSION:git" -h -c "$PROJECT_DIR"
tmux send-keys -t "$SESSION:git.0" 'git status' C-m
tmux send-keys -t "$SESSION:git.1" 'git log --oneline -10' C-m

# Create server window
tmux new-window -t "$SESSION" -n server -c "$PROJECT_DIR"
tmux split-window -t "$SESSION:server" -v -c "$PROJECT_DIR"
tmux send-keys -t "$SESSION:server.0" 'npm run dev' C-m
tmux send-keys -t "$SESSION:server.1" 'npm run test -- --watch' C-m

# Create monitoring window
tmux new-window -t "$SESSION" -n monitor
tmux send-keys -t "$SESSION:monitor" 'htop' C-m

# Return to editor
tmux select-window -t "$SESSION:editor"

# Set session-specific options
tmux set-option -t "$SESSION" status-left "[$PROJECT_NAME] "
tmux set-option -t "$SESSION" @project_dir "$PROJECT_DIR"

# Display info
tmux display -t "$SESSION" "Project session $PROJECT_NAME created"

# Attach
tmux attach-session -t "$SESSION"
```

Use it:

```bash theme={null}
./project-session.sh myapp ~/dev/myapp
```
