Tools: Build a reusable Terminator layout with pre-loaded commands per pane (2026)

Tools: Build a reusable Terminator layout with pre-loaded commands per pane (2026)

Why Terminator and not tmux? If you regularly work across multiple servers, environments, or services, you probably know this dance: open a terminal, split it three ways, type the same SSH command in one pane, the same tail -f in another, and a ping in the third. Every time. For every host. This post walks through building a single shell script that opens

Terminator with a custom layout — three panes, each with its own title and a list of commands pre-loaded into shell history, ready to fire with a single up arrow. You invoke it as ./multi-pane.sh prod and the argument propagates intoevery pane title and command. The same script works for staging, dev, orany environment label you want. tmux is more powerful, scriptable, and works over SSH. But tmux has alearning curve, lives inside one terminal window, and isn't something mostpeople want to launch from a desktop shortcut. Terminator is a GUI terminal emulator that supports persistent layouts via aconfig file. It's perfect when you want a desktop launcher that opens aspecific multi-pane setup with one command — and you want the result to feel

like a normal application window, not an embedded multiplexer. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to ? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

#!/bin/bash # # multi-pane.sh — Abre Terminator con un layout de 3 paneles personalizables, # cada uno con su propio título y comandos precargados en el historial # (listos para ejecutar con flecha arriba). # # Uso: ./multi-pane.sh <argumento> # # El argumento se sustituye en los títulos y comandos de cada panel. # Útil para flujos donde alternás entre múltiples hosts/entornos. # set -euo pipefail ARG=${1:?Uso: $(basename "$0") <argumento>} CONFIG="$HOME/.config/terminator/config" RC_LEFT=/tmp/multi-pane-rc-left RC_TOP_RIGHT=/tmp/multi-pane-rc-top-right RC_BOTTOM_RIGHT=/tmp/multi-pane-rc-bottom-right # --------------------------------------------------------------------------- # gen_rc: genera un rcfile temporal que será cargado por bash con --rcfile. # Hace dos cosas: # 1) Sourcea ~/.bashrc para mantener el entorno habitual del usuario. # 2) Inyecta cada comando recibido como argumento en el historial mediante # `history -s`, sin ejecutarlo. El último argumento queda más cerca del # prompt (1 sola flecha arriba para acceder). # --------------------------------------------------------------------------- gen_rc() { local rcfile=$1 shift { echo '[ -f "$HOME/.bashrc" ] && source "$HOME/.bashrc"' for cmd in "$@"; do echo "history -s \"$cmd\"" done } > "$rcfile" } # Comandos por panel — personalizá según tu flujo. # El último argumento es el primero al que accedés con flecha arriba. gen_rc "$RC_LEFT" \ "echo 'segundo comando'" \ "echo 'primer comando (flecha arriba lo trae)'" gen_rc "$RC_TOP_RIGHT" \ "ls -la" \ "pwd" gen_rc "$RC_BOTTOM_RIGHT" \ "date" # --------------------------------------------------------------------------- # Inyección del layout en el config de Terminator. # # Se inserta directamente en ~/.config/terminator/config en lugar de usar # un archivo separado con `-g`. ¿Por qué? Porque `-g` reemplaza la config # completa, perdiendo fuente, colores y atajos personales del usuario. # Inyectando en el config real, todo se hereda automáticamente. # --------------------------------------------------------------------------- mkdir -p "$(dirname "$CONFIG")" touch "$CONFIG" # Borrar layout previo con el mismo nombre (idempotencia: el script se puede # ejecutar múltiples veces sin acumular layouts duplicados). python3 - "$CONFIG" <<'PYEOF' import sys, re path = sys.argv[1] with open(path) as f: content = f.read() pattern = re.compile( r'(^ \[\[multi_pane\]\].*?)(?=^ \[\[|^\[|\Z)', re.MULTILINE | re.DOTALL ) content = pattern.sub('', content) with open(path, 'w') as f: f.write(content) PYEOF # Asegurar que exista la sección [layouts] grep -q '^\[layouts\]' "$CONFIG" || echo -e "\n[layouts]" >> "$CONFIG" # Insertar el layout nuevo justo después de [layouts]. # El layout define una división horizontal (HPaned) al 50%, y el lado # derecho se divide verticalmente (VPaned) en dos paneles. # # ┌─────────────┬─────────────┐ # │ │ TOP-RIGHT │ # │ LEFT ├─────────────┤ # │ │BOTTOM-RIGHT │ # └─────────────┴─────────────┘ python3 - "$CONFIG" "$ARG" "$RC_LEFT" "$RC_TOP_RIGHT" "$RC_BOTTOM_RIGHT" <<'PYEOF' import sys path, arg, rc_l, rc_tr, rc_br = sys.argv[1:] layout = f""" [[multi_pane]] [[[window0]]] type = Window parent = "" title = Multi-pane {arg} [[[child1]]] type = HPaned parent = window0 ratio = 0.5 [[[left]]] type = Terminal parent = child1 order = 0 profile = default title = LEFT - {arg} command = bash --rcfile {rc_l} [[[child2]]] type = VPaned parent = child1 order = 1 ratio = 0.5 [[[top_right]]] type = Terminal parent = child2 order = 0 profile = default title = TOP RIGHT - {arg} command = bash --rcfile {rc_tr} [[[bottom_right]]] type = Terminal parent = child2 order = 1 profile = default title = BOTTOM RIGHT - {arg} command = bash --rcfile {rc_br} """ with open(path) as f: content = f.read() content = content.replace('[layouts]\n', '[layouts]\n' + layout, 1) with open(path, 'w') as f: f.write(content) PYEOF # Lanzar Terminator desconectado de la shell padre: # --no-dbus : evita que una instancia existente capture la invocación # --maximise : abre la ventana maximizada # nohup + & : sobrevive al cierre de la shell padre # disown : libera la shell para que pueda cerrarse sin advertencias nohup terminator --no-dbus --maximise -l multi_pane </dev/null >/dev/null 2>&1 & disown #!/bin/bash # # multi-pane.sh — Abre Terminator con un layout de 3 paneles personalizables, # cada uno con su propio título y comandos precargados en el historial # (listos para ejecutar con flecha arriba). # # Uso: ./multi-pane.sh <argumento> # # El argumento se sustituye en los títulos y comandos de cada panel. # Útil para flujos donde alternás entre múltiples hosts/entornos. # set -euo pipefail ARG=${1:?Uso: $(basename "$0") <argumento>} CONFIG="$HOME/.config/terminator/config" RC_LEFT=/tmp/multi-pane-rc-left RC_TOP_RIGHT=/tmp/multi-pane-rc-top-right RC_BOTTOM_RIGHT=/tmp/multi-pane-rc-bottom-right # --------------------------------------------------------------------------- # gen_rc: genera un rcfile temporal que será cargado por bash con --rcfile. # Hace dos cosas: # 1) Sourcea ~/.bashrc para mantener el entorno habitual del usuario. # 2) Inyecta cada comando recibido como argumento en el historial mediante # `history -s`, sin ejecutarlo. El último argumento queda más cerca del # prompt (1 sola flecha arriba para acceder). # --------------------------------------------------------------------------- gen_rc() { local rcfile=$1 shift { echo '[ -f "$HOME/.bashrc" ] && source "$HOME/.bashrc"' for cmd in "$@"; do echo "history -s \"$cmd\"" done } > "$rcfile" } # Comandos por panel — personalizá según tu flujo. # El último argumento es el primero al que accedés con flecha arriba. gen_rc "$RC_LEFT" \ "echo 'segundo comando'" \ "echo 'primer comando (flecha arriba lo trae)'" gen_rc "$RC_TOP_RIGHT" \ "ls -la" \ "pwd" gen_rc "$RC_BOTTOM_RIGHT" \ "date" # --------------------------------------------------------------------------- # Inyección del layout en el config de Terminator. # # Se inserta directamente en ~/.config/terminator/config en lugar de usar # un archivo separado con `-g`. ¿Por qué? Porque `-g` reemplaza la config # completa, perdiendo fuente, colores y atajos personales del usuario. # Inyectando en el config real, todo se hereda automáticamente. # --------------------------------------------------------------------------- mkdir -p "$(dirname "$CONFIG")" touch "$CONFIG" # Borrar layout previo con el mismo nombre (idempotencia: el script se puede # ejecutar múltiples veces sin acumular layouts duplicados). python3 - "$CONFIG" <<'PYEOF' import sys, re path = sys.argv[1] with open(path) as f: content = f.read() pattern = re.compile( r'(^ \[\[multi_pane\]\].*?)(?=^ \[\[|^\[|\Z)', re.MULTILINE | re.DOTALL ) content = pattern.sub('', content) with open(path, 'w') as f: f.write(content) PYEOF # Asegurar que exista la sección [layouts] grep -q '^\[layouts\]' "$CONFIG" || echo -e "\n[layouts]" >> "$CONFIG" # Insertar el layout nuevo justo después de [layouts]. # El layout define una división horizontal (HPaned) al 50%, y el lado # derecho se divide verticalmente (VPaned) en dos paneles. # # ┌─────────────┬─────────────┐ # │ │ TOP-RIGHT │ # │ LEFT ├─────────────┤ # │ │BOTTOM-RIGHT │ # └─────────────┴─────────────┘ python3 - "$CONFIG" "$ARG" "$RC_LEFT" "$RC_TOP_RIGHT" "$RC_BOTTOM_RIGHT" <<'PYEOF' import sys path, arg, rc_l, rc_tr, rc_br = sys.argv[1:] layout = f""" [[multi_pane]] [[[window0]]] type = Window parent = "" title = Multi-pane {arg} [[[child1]]] type = HPaned parent = window0 ratio = 0.5 [[[left]]] type = Terminal parent = child1 order = 0 profile = default title = LEFT - {arg} command = bash --rcfile {rc_l} [[[child2]]] type = VPaned parent = child1 order = 1 ratio = 0.5 [[[top_right]]] type = Terminal parent = child2 order = 0 profile = default title = TOP RIGHT - {arg} command = bash --rcfile {rc_tr} [[[bottom_right]]] type = Terminal parent = child2 order = 1 profile = default title = BOTTOM RIGHT - {arg} command = bash --rcfile {rc_br} """ with open(path) as f: content = f.read() content = content.replace('[layouts]\n', '[layouts]\n' + layout, 1) with open(path, 'w') as f: f.write(content) PYEOF # Lanzar Terminator desconectado de la shell padre: # --no-dbus : evita que una instancia existente capture la invocación # --maximise : abre la ventana maximizada # nohup + & : sobrevive al cierre de la shell padre # disown : libera la shell para que pueda cerrarse sin advertencias nohup terminator --no-dbus --maximise -l multi_pane </dev/null >/dev/null 2>&1 & disown #!/bin/bash # # multi-pane.sh — Abre Terminator con un layout de 3 paneles personalizables, # cada uno con su propio título y comandos precargados en el historial # (listos para ejecutar con flecha arriba). # # Uso: ./multi-pane.sh <argumento> # # El argumento se sustituye en los títulos y comandos de cada panel. # Útil para flujos donde alternás entre múltiples hosts/entornos. # set -euo pipefail ARG=${1:?Uso: $(basename "$0") <argumento>} CONFIG="$HOME/.config/terminator/config" RC_LEFT=/tmp/multi-pane-rc-left RC_TOP_RIGHT=/tmp/multi-pane-rc-top-right RC_BOTTOM_RIGHT=/tmp/multi-pane-rc-bottom-right # --------------------------------------------------------------------------- # gen_rc: genera un rcfile temporal que será cargado por bash con --rcfile. # Hace dos cosas: # 1) Sourcea ~/.bashrc para mantener el entorno habitual del usuario. # 2) Inyecta cada comando recibido como argumento en el historial mediante # `history -s`, sin ejecutarlo. El último argumento queda más cerca del # prompt (1 sola flecha arriba para acceder). # --------------------------------------------------------------------------- gen_rc() { local rcfile=$1 shift { echo '[ -f "$HOME/.bashrc" ] && source "$HOME/.bashrc"' for cmd in "$@"; do echo "history -s \"$cmd\"" done } > "$rcfile" } # Comandos por panel — personalizá según tu flujo. # El último argumento es el primero al que accedés con flecha arriba. gen_rc "$RC_LEFT" \ "echo 'segundo comando'" \ "echo 'primer comando (flecha arriba lo trae)'" gen_rc "$RC_TOP_RIGHT" \ "ls -la" \ "pwd" gen_rc "$RC_BOTTOM_RIGHT" \ "date" # --------------------------------------------------------------------------- # Inyección del layout en el config de Terminator. # # Se inserta directamente en ~/.config/terminator/config en lugar de usar # un archivo separado con `-g`. ¿Por qué? Porque `-g` reemplaza la config # completa, perdiendo fuente, colores y atajos personales del usuario. # Inyectando en el config real, todo se hereda automáticamente. # --------------------------------------------------------------------------- mkdir -p "$(dirname "$CONFIG")" touch "$CONFIG" # Borrar layout previo con el mismo nombre (idempotencia: el script se puede # ejecutar múltiples veces sin acumular layouts duplicados). python3 - "$CONFIG" <<'PYEOF' import sys, re path = sys.argv[1] with open(path) as f: content = f.read() pattern = re.compile( r'(^ \[\[multi_pane\]\].*?)(?=^ \[\[|^\[|\Z)', re.MULTILINE | re.DOTALL ) content = pattern.sub('', content) with open(path, 'w') as f: f.write(content) PYEOF # Asegurar que exista la sección [layouts] grep -q '^\[layouts\]' "$CONFIG" || echo -e "\n[layouts]" >> "$CONFIG" # Insertar el layout nuevo justo después de [layouts]. # El layout define una división horizontal (HPaned) al 50%, y el lado # derecho se divide verticalmente (VPaned) en dos paneles. # # ┌─────────────┬─────────────┐ # │ │ TOP-RIGHT │ # │ LEFT ├─────────────┤ # │ │BOTTOM-RIGHT │ # └─────────────┴─────────────┘ python3 - "$CONFIG" "$ARG" "$RC_LEFT" "$RC_TOP_RIGHT" "$RC_BOTTOM_RIGHT" <<'PYEOF' import sys path, arg, rc_l, rc_tr, rc_br = sys.argv[1:] layout = f""" [[multi_pane]] [[[window0]]] type = Window parent = "" title = Multi-pane {arg} [[[child1]]] type = HPaned parent = window0 ratio = 0.5 [[[left]]] type = Terminal parent = child1 order = 0 profile = default title = LEFT - {arg} command = bash --rcfile {rc_l} [[[child2]]] type = VPaned parent = child1 order = 1 ratio = 0.5 [[[top_right]]] type = Terminal parent = child2 order = 0 profile = default title = TOP RIGHT - {arg} command = bash --rcfile {rc_tr} [[[bottom_right]]] type = Terminal parent = child2 order = 1 profile = default title = BOTTOM RIGHT - {arg} command = bash --rcfile {rc_br} """ with open(path) as f: content = f.read() content = content.replace('[layouts]\n', '[layouts]\n' + layout, 1) with open(path, 'w') as f: f.write(content) PYEOF # Lanzar Terminator desconectado de la shell padre: # --no-dbus : evita que una instancia existente capture la invocación # --maximise : abre la ventana maximizada # nohup + & : sobrevive al cierre de la shell padre # disown : libera la shell para que pueda cerrarse sin advertencias nohup terminator --no-dbus --maximise -l multi_pane </dev/null >/dev/null 2>&1 & disown ./multi-pane.sh prod - Joined Apr 30, 2026