tmux-management 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. #!/usr/bin/env bash
  2. # Open a tiled tmux window with one pane per host each in its own tmux session
  3. # The local host is always the last (active) pane.
  4. # Copyright 2021-2025 Bryan C. Roessler
  5. # Licensed under the Apache License, Version 2.0
  6. set -euo pipefail
  7. # Configuration (override with env vars if desired)
  8. HOSTS=(workstation laptop) # hosts in pane order
  9. REMOTE_SESSION=${REMOTE_SESSION:-main} # tmux session on remotes
  10. SYNCHRONIZE=${SYNCHRONIZE:-1} # 1 = broadcast keystrokes
  11. INCLUDE_LOCAL=${INCLUDE_LOCAL:-1} # 0 = skip local host
  12. LOCAL_SHELL_ONLY=${LOCAL_SHELL_ONLY:-0} # 1 = plain shell locally
  13. DEBUG=${DEBUG:-0}
  14. debug() { if (( DEBUG )); then echo "Debug: $*"; fi; }
  15. # Returns 0 if $2 is found in nameref array $1
  16. array_contains() {
  17. local -n arr=$1
  18. local needle=$2
  19. for element in "${arr[@]}"; do
  20. [[ "$element" == "$needle" ]] && return 0
  21. done
  22. return 1
  23. }
  24. LOCAL=$(hostname -s)
  25. # Build TARGETS list so that LOCAL is always last
  26. TARGETS=()
  27. for h in "${HOSTS[@]}"; do
  28. [[ $h != "$LOCAL" ]] && TARGETS+=("$h")
  29. done
  30. if (( INCLUDE_LOCAL )); then
  31. TARGETS+=("$LOCAL")
  32. fi
  33. (( ${#TARGETS[@]} )) || { echo "No hosts to connect to."; exit 1; }
  34. SESSION=$(IFS=-; echo "${TARGETS[*]}")
  35. debug "Session : $SESSION"
  36. debug "Targets : ${TARGETS[*]}"
  37. # Re‑attach if session already exists
  38. if tmux has-session -t "$SESSION" 2>/dev/null; then
  39. exec tmux attach -t "$SESSION"
  40. fi
  41. # Builds the command that will run inside a pane
  42. open_cmd() {
  43. local tgt=$1
  44. if [[ $tgt == "$LOCAL" ]]; then
  45. if (( LOCAL_SHELL_ONLY )); then
  46. printf '%q -l' "${SHELL:-bash}"
  47. else
  48. printf 'tmux -L %q new -A -s %q' "${SESSION}_local" "$REMOTE_SESSION"
  49. fi
  50. else
  51. printf 'ssh -t %q tmux new -A -s %q' "$tgt" "$REMOTE_SESSION"
  52. fi
  53. }
  54. # Create the first pane
  55. tmux new-session -d -s "$SESSION" -n "$SESSION" "$(open_cmd "${TARGETS[0]}")"
  56. # Create remaining panes
  57. for tgt in "${TARGETS[@]:1}"; do
  58. tmux split-window -t "$SESSION:0" -h "$(open_cmd "$tgt")"
  59. done
  60. tmux select-layout -t "$SESSION:0" tiled
  61. ((SYNCHRONIZE)) && tmux setw -t "$SESSION:0" synchronize-panes on
  62. # Activate the last pane (local host)
  63. local_index=$(( ${#TARGETS[@]} - 1 ))
  64. tmux select-pane -t "$SESSION:0.$local_index"
  65. exec tmux attach -t "$SESSION"