Introduction

Yesterday, I came across a post where someone was running tests, and their SSH session disconnected midway through. Using tmux can prevent this by allowing your processes to continue running even if the SSH connection drops. Of course, you could also use screen, as they are quite similar. This script is intended for beginners, or for those who can’t remember the parameters or simply prefer not to type out the full commands. Experts can feel free to move along.

Script

#!/usr/bin/env bash

set -Eeuo pipefail

has_cmd() { command -v "$1" >/dev/null 2>&1; }

detect_pm() {
  if has_cmd apt-get; then echo apt; return; fi
  if has_cmd dnf;     then echo dnf; return; fi
  if has_cmd yum;     then echo yum; return; fi
  if has_cmd pacman;  then echo pacman; return; fi
  if has_cmd zypper;  then echo zypper; return; fi
  if has_cmd apk;     then echo apk; return; fi
  if has_cmd brew;    then echo brew; return; fi
  echo none
}

install_tmux() {
  local pm="$1" sudo_cmd=""
  if [[ ${EUID:-$(id -u)} -ne 0 ]] && [[ "$pm" != "brew" ]]; then sudo_cmd="sudo"; fi
  case "$pm" in
    apt)     $sudo_cmd apt-get update -y && $sudo_cmd apt-get install -y tmux ;;
    dnf)     $sudo_cmd dnf install -y tmux ;;
    yum)     $sudo_cmd yum install -y tmux ;;
    pacman)  $sudo_cmd pacman -Sy --noconfirm tmux ;;
    zypper)  $sudo_cmd zypper --non-interactive install tmux ;;
    apk)     $sudo_cmd apk add --no-cache tmux ;;
    brew)    brew install tmux ;;
    *) echo "Could not auto-install tmux: No supported package manager (apt/dnf/yum/pacman/zypper/apk/brew) detected." >&2; exit 1 ;;
  esac
}

ensure_tmux() {
  if ! has_cmd tmux; then
    echo "tmux not detected, attempting to install automatically..."
    local pm; pm="$(detect_pm)"
    install_tmux "$pm"
  fi
}

create_and_run() {
  local session="$1" cmd="$2"

  if tmux has-session -t "$session" 2>/dev/null; then
    echo "Session '$session' already exists. Please choose a different session name." >&2
    exit 2
  fi

  tmux new-session -d -s "$session"

  local line
  line="$cmd; EXIT_CODE=\$?; tmux kill-session -t \"$session\"; exit \$EXIT_CODE"

  tmux send-keys -t "$session" -l "$line"
  tmux send-keys -t "$session" C-m

  cat <<EOF
Command started in tmux session '$session':
  $cmd

To view live output: tmux attach -t $session
To detach from the session (without interrupting the task): Press Ctrl+b then d inside tmux.
The session will be automatically terminated upon task completion.
EOF
}

main() {
  ensure_tmux

  local session="" cmd=""

  if [[ "${1-}" == "-n" ]]; then session="$2"; shift 2; fi
  if [[ "${1-}" == "-c" ]]; then cmd="$2"; shift 2; fi
  if [[ $# -gt 0 ]]; then
    cmd="${cmd:+$cmd }$*"
  fi

  if [[ -z "$session" ]]; then
    read -r -p "Enter a name for the tmux session: " session
    session="${session:-job-$(date +%Y%m%d%H%M%S)}"
  fi
  if [[ -z "$cmd" ]]; then
    read -r -p "Enter the command to execute in tmux: " cmd
  fi
  if [[ -z "$cmd" ]]; then
    echo "No command provided to execute." >&2
    exit 3
  fi

  create_and_run "$session" "$cmd"
}

main "$@"

P.S.

How to Use

Log in to your server, save this script as run_in_tmux.sh, and grant it execute permissions with chmod +x run_in_tmux.sh. Then you’re ready to run it.

Examples

run_in_tmux.sh [-n <session_name>] [-c "<command_string>"] [command_and_args...]

# Interactive mode (follow the prompts)
./run_in_tmux.sh

# Specify session name + entire command as a string
./run_in_tmux.sh -n rclone-copy -c 'rclone copy src dst --progress'

# Omit -c and pass the command directly at the end
./run_in_tmux.sh -n rclone-copy rclone copy src dst --progress

Exit Codes

Internal error codes: 1 (failed to auto-install tmux), 2 (session already exists), 3 (no command provided)

A Semi-Automated Script for tmux

Author

Shayne Wong

Publish Date

10 - 08 - 2025

License

Shayne Wong

Avatar
Shayne Wong

All time is no time when it is past.