Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Expert tmux session, window, and pane management for terminal multiplexing, persistent remote workflows, and shell scripting automation.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 87% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 201% | 0% |
| case-22 | ✓→✗ | ▼ Worse | 223% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 236% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 140% | 0% |
tmux keeps terminal sessions alive across SSH disconnects, splits work across multiple panes, and enables fully scriptable terminal automation. This skill covers session management, window/pane layout, keybinding patterns, and using tmux non-interactively from shell scripts — essential for remote servers, long-running jobs, and automated workflows.
tmux commands from bash scripts without user interactiontmux has three hierarchy levels: sessions (top level, survives disconnects), windows (tabs within a session), and panes (splits within a window). Everything is controllable from outside via tmux <command> or from inside via the prefix key (Ctrl-b by default).
bash# Create a new named session tmux new-session -s work # Create detached (background) session tmux new-session -d -s work # Create detached session and start a command tmux new-session -d -s build -x 220 -y 50 "make all" # Attach to a session tmux attach -t work tmux attach # attaches to most recent session # List all sessions tmux list-sessions tmux ls # Detach from inside tmux # Prefix + d (Ctrl-b d) # Kill a session tmux kill-session -t work # Kill all sessions except the current one tmux kill-session -a # Rename a session from outside tmux rename-session -t old-name new-name # Switch to another session from outside tmux switch-client -t other-session # Check if a session exists (useful in scripts) tmux has-session -t work 2>/dev/null && echo "exists"
bash# Create a new window in the current session tmux new-window -t work -n "logs" # Create a window running a specific command tmux new-window -t work:3 -n "server" "python -m http.server 8080" # List windows tmux list-windows -t work # Select (switch to) a window tmux select-window -t work:logs tmux select-window -t work:2 # by index # Rename a window tmux rename-window -t work:2 "editor" # Kill a window tmux kill-window -t work:logs # Move window to a new index tmux move-window -s work:3 -t work:1 # From inside tmux: # Prefix + c — new window # Prefix + , — rename window # Prefix + & — kill window # Prefix + n/p — next/previous window # Prefix + 0-9 — switch to window by number
bash# Split pane vertically (left/right) tmux split-window -h -t work:1 # Split pane horizontally (top/bottom) tmux split-window -v -t work:1 # Split and run a command tmux split-window -h -t work:1 "tail -f /var/log/syslog" # Select a pane by index tmux select-pane -t work:1.0 # Resize panes tmux resize-pane -t work:1.0 -R 20 # expand right by 20 cols tmux resize-pane -t work:1.0 -D 10 # shrink down by 10 rows tmux resize-pane -Z # toggle zoom (fullscreen) # Swap panes tmux swap-pane -s work:1.0 -t work:1.1 # Kill a pane tmux kill-pane -t work:1.1 # From inside tmux: # Prefix + % — split vertical # Prefix + " — split horizontal # Prefix + arrow — navigate panes # Prefix + z — zoom/unzoom current pane # Prefix + x — kill pane # Prefix + {/} — swap pane with previous/next
bash# Send a command to a specific pane and press Enter tmux send-keys -t work:1.0 "ls -la" Enter # Run a command in a background pane without attaching tmux send-keys -t work:editor "vim src/main.py" Enter # Send Ctrl+C to stop a running process tmux send-keys -t work:1.0 C-c # Send text without pressing Enter (useful for pre-filling prompts) tmux send-keys -t work:1.0 "git commit -m '" # Clear a pane tmux send-keys -t work:1.0 "clear" Enter # Check what's in a pane (capture its output) tmux capture-pane -t work:1.0 -p tmux capture-pane -t work:1.0 -p | grep "ERROR"
This is the most powerful pattern: create a fully configured multi-pane workspace from a single script.
bash#!/usr/bin/env bash set -euo pipefail SESSION="dev" # Bail if session already exists tmux has-session -t "$SESSION" 2>/dev/null && { echo "Session $SESSION already exists. Attaching..." tmux attach -t "$SESSION" exit 0 } # Create session with first window tmux new-session -d -s "$SESSION" -n "editor" -x 220 -y 50 # Window 1: editor + test runner side by side tmux send-keys -t "$SESSION:editor" "vim ." Enter tmux split-window -h -t "$SESSION:editor" tmux send-keys -t "$SESSION:editor.1" "npm test -- --watch" Enter tmux select-pane -t "$SESSION:editor.0" # Window 2: server logs tmux new-window -t "$SESSION" -n "server" tmux send-keys -t "$SESSION:server" "docker compose up" Enter tmux split-window -v -t "$SESSION:server" tmux send-keys -t "$SESSION:server.1" "tail -f logs/app.log" Enter # Window 3: general shell tmux new-window -t "$SESSION" -n "shell" # Focus first window tmux select-window -t "$SESSION:editor" # Attach tmux attach -t "$SESSION"
~/.tmux.conf)bash# Change prefix to Ctrl-a (screen-style) unbind C-b set -g prefix C-a bind C-a send-prefix # Enable mouse support set -g mouse on # Start window/pane numbering at 1 set -g base-index 1 setw -g pane-base-index 1 # Renumber windows when one is closed set -g renumber-windows on # Increase scrollback buffer set -g history-limit 50000 # Use vi keys in copy mode setw -g mode-keys vi # Faster key repetition set -s escape-time 0 # Reload config without restarting bind r source-file ~/.tmux.conf \; display "Config reloaded" # Intuitive splits: | and - bind | split-window -h -c "#{pane_current_path}" bind - split-window -v -c "#{pane_current_path}" # New windows open in current directory bind c new-window -c "#{pane_current_path}" # Status bar set -g status-right "#{session_name} | %H:%M %d-%b" set -g status-interval 5
bash# Enter copy mode (scroll up through output) # Prefix + [ # In vi mode: # / to search forward, ? to search backward # Space to start selection, Enter to copy # q to exit copy mode # Paste the most recent buffer # Prefix + ] # List paste buffers tmux list-buffers # Show the most recent buffer tmux show-buffer # Save buffer to a file tmux save-buffer /tmp/tmux-output.txt # Load a file into a buffer tmux load-buffer /tmp/data.txt # Pipe pane output to a command tmux pipe-pane -t work:1.0 "cat >> ~/session.log"
bash# Idempotent session: create or attach ensure_session() { local name="$1" tmux has-session -t "$name" 2>/dev/null \ || tmux new-session -d -s "$name" tmux attach -t "$name" } # Run a command in a new background window and tail its output run_bg() { local session="${1:-main}" cmd="${*:2}" tmux new-window -t "$session" -n "bg-$$" tmux send-keys -t "$session:bg-$$" "$cmd" Enter } # Wait for a pane to produce specific output (polling) wait_for_output() { local target="$1" pattern="$2" timeout="${3:-30}" local elapsed=0 while (( elapsed < timeout )); do tmux capture-pane -t "$target" -p | grep -q "$pattern" && return 0 sleep 1 (( elapsed++ )) done return 1 } # Kill all background windows matching a name prefix kill_bg_windows() { local session="$1" prefix="${2:-bg-}" tmux list-windows -t "$session" -F "#W" \ | grep "^${prefix}" \ | while read -r win; do tmux kill-window -t "${session}:${win}" done }
bash# SSH and immediately attach to an existing session ssh user@host -t "tmux attach -t work || tmux new-session -s work" # Run a command on remote host inside a tmux session (fire and forget) ssh user@host "tmux new-session -d -s deploy 'bash /opt/deploy.sh'" # Watch the remote session output from another terminal ssh user@host -t "tmux attach -t deploy -r" # read-only attach # Pair programming: share a session (both users attach to the same session) # User 1: tmux new-session -s shared # User 2 (same server): tmux attach -t shared
-s name) in scripts — unnamed sessions are hard to target reliablytmux has-session -t name 2>/dev/null before creating to make scripts idempotent-x and -y when creating detached sessions to give panes a proper size for commands that check terminal dimensionssend-keys ... Enter for automation rather than piping stdin — it works even when the target pane is running an interactive program~/.tmux.conf in version control for reproducibility across machinesbind -n for bindings that don't need the prefix, but only for keys that don't conflict with application shortcutssend-keys executes commands in a pane without confirmation — verify the target (-t session:window.pane) before use in scripts to avoid sending keystrokes to the wrong pane-r) is appropriate when sharing sessions with others to prevent accidental inputtmux commands from a script fail with "no server running"Solution: Start the server first with tmux start-server, or create a detached session before running other commands.
Solution: Pass explicit dimensions: tmux new-session -d -s name -x 200 -y 50.
send-keys types the text but doesn't run the commandSolution: Ensure you pass Enter (capital E) as a second argument: tmux send-keys -t target "cmd" Enter.
Solution: Guard with tmux has-session -t name 2>/dev/null || tmux new-session -d -s name.
Solution: Confirm mode-keys vi or mode-keys emacs is set to match your preference in ~/.tmux.conf.
@bash-pro — Writing the shell scripts that orchestrate tmux sessions@bash-linux — General Linux terminal patterns used inside tmux panes@ssh — Combining tmux with SSH for persistent remote workflowsOther measured skills in the registry, with their headline benchmark lift.