Learning Platform
Глоссарий Troubleshooting
Урок 20.04 · 22 мин
Средний
tmuxTerminalSSHMultiplexingProductivity

tmux: terminal multiplexing

Сценарий: ты подключился к production server по SSH, запустил долгий ETL-скрипт (3 часа). Закрыл laptop. SSH-соединение разорвалось — скрипт убит сигналом SIGHUP, процесс умер. Утром выясняешь, что job не доделался, данные неполные.

Или: ты пишешь Airflow DAG в одной vim-сессии, нужно посмотреть лог в другом терминале, проверить SQL в третьем. Открываешь три SSH-сессии — три tab бараBraga, три commands ssh, три прохода аутентификации.

tmux решает обе проблемы. Это terminal multiplexer: создаёт persistent сессии, которые продолжают работать даже после disconnect, и позволяет иметь множество окон/панелей внутри одного соединения. Закрыл laptop — tmux session живёт, переподключился — tmux attach и ты снова там.

В этом уроке: установка, основные команды (sessions, windows, panes), key bindings, конфигурация, и почему каждый DE должен освоить tmux на первой неделе работы.


Установка

# Debian/Ubuntu:
sudo apt install tmux

# macOS:
brew install tmux

# Проверка:
tmux -V
# tmux 3.4 или новее

Концептуальная модель

tmux иерархия: server -> sessions -> windows -> panes
serverОдин tmux server на пользователя на машину. Запускается автоматически при первой команде tmux. Живёт пока есть session
sessionЛогическая группа окон. Обычно — один проект или задача. Например: session 'etl-prod', 'airflow-dev'
sessionПараллельные сессии — для разных проектов, разных серверов
windowВнутри session — несколько окон (tabs). Каждое окно = full-screen рабочее пространство
windowПереключение через prefix + цифру или prefix + n/p
windowОкно может содержать несколько pane (split-screen)
paneВнутри окна — разделить экран на части (panes). Каждый pane — отдельный shell
paneГоризонтальный split — две панели сверху и снизу
paneВертикальный split — две панели слева и справа

Полная иерархия: один server, в нём sessions, в каждой session windows (как tabs), в каждом window можно делать panes (split-screen).


Базовый workflow

# Создать новую сессию:
tmux

# Или с именем:
tmux new -s work

# Внутри сессии: командная строка как обычно
$ ls
$ vim file.py

# Detach (выйти, оставив сессию работать):
# Жмём prefix + d (по умолчанию Ctrl-b, потом d)

# Список сессий:
tmux ls

# Reattach к последней:
tmux attach
# или конкретной:
tmux attach -t work

# Убить сессию:
tmux kill-session -t work

Detach/attach — main feature

Detach — это отключиться, но не убить. Все процессы продолжают работать. Это спасает жизнь:

# На сервере по SSH:
$ ssh prod-server
$ tmux new -s nightly_etl
$ python /opt/etl/long_job.py    # 3-hour job
# Жмём Ctrl-b d                  # detach
$ exit                            # SSH disconnect

# ETL продолжает работать в tmux session на сервере.

# Утром:
$ ssh prod-server
$ tmux attach -t nightly_etl     # снова в сессии
# Видишь логи job, или ждёшь окончания

Это — главный use case tmux для DE. Без tmux SSH disconnect = SIGHUP = job died.

SSH — ключи, туннели и сохранение соединения

Key bindings: prefix

tmux команды triggers через prefix key + другая клавиша. Default prefix — Ctrl-b. Многие пользователи переназначают на Ctrl-a (как в GNU screen).

Ctrl-b d         # detach
Ctrl-b c         # create new window
Ctrl-b n         # next window
Ctrl-b p         # previous window
Ctrl-b 0..9      # switch to window by number
Ctrl-b ,         # rename current window
Ctrl-b w         # list windows (с preview)
Ctrl-b &         # kill current window

Panes

Ctrl-b %         # split horizontal (left | right)
Ctrl-b "         # split vertical (top / bottom)
Ctrl-b o         # next pane
Ctrl-b ;         # toggle between two recent panes
Ctrl-b arrows    # move to pane in direction
Ctrl-b z         # zoom current pane (fullscreen, toggle)
Ctrl-b x         # kill current pane
Ctrl-b q         # show pane numbers (then press number to focus)
Ctrl-b {         # swap pane left
Ctrl-b }         # swap pane right
Ctrl-b spacebar  # rotate pane layouts (presets)

Sessions

Ctrl-b s         # list sessions (interactive)
Ctrl-b $         # rename current session
Ctrl-b (         # previous session
Ctrl-b )         # next session
Ctrl-b D         # choose session to detach (если есть multi-user)

Copy mode

Ctrl-b [         # enter copy mode (scroll back, search)
                 # В copy mode: arrows для скролла, /text для search
                 # Space — start selection, Enter — copy
Ctrl-b ]         # paste

# Vim-style keybindings (если настроено):
v                # start selection
y                # copy

Реальный DE workflow: production debugging

$ ssh prod-airflow
$ tmux new -s debug

# Окно 0 (rename: airflow-logs):
$ tail -f /var/log/airflow/scheduler.log

# Создать новое окно:
# Ctrl-b c
# Rename: Ctrl-b , -> "db-query"
$ psql -h analytics-db -U airflow
analytics=# SELECT count(*) FROM raw.user_events WHERE date = current_date;

# Ctrl-b c (третье окно: "fs")
$ cd /opt/airflow/dags
$ ls -lha *user_events*

# Split current window vertically (Ctrl-b "):
# Now two panes: dags listing top, htop bottom
$ htop

# Detach (Ctrl-b d), закрыл laptop. Session живёт.
# Через 30 минут переподключился:
$ ssh prod-airflow
$ tmux attach -t debug
# Всё на месте: 3 окна с logs, db, fs+htop. Production debugging session preserved.
TIP

Convention: один tmux session — одна задача. Не пихай всё в одну session. tmux new -s nightly_etl, tmux new -s migration, tmux new -s incident-2026-05-13. Когда задача закрыта — tmux kill-session. Это и organize, и encourages tidiness.


Конфигурация: ~/.tmux.conf

Default key bindings бесят опытных пользователей. Минимальная сustomization:

# ~/.tmux.conf

# 1. Change prefix to Ctrl-a (как GNU screen, проще достичь):
unbind C-b
set -g prefix C-a
bind C-a send-prefix

# 2. Start window numbering from 1 (0 на дальнем краю клавиатуры):
set -g base-index 1
setw -g pane-base-index 1

# 3. Renumber windows on close (чтобы не было пропусков):
set -g renumber-windows on

# 4. Mouse mode:
set -g mouse on

# 5. 256 colors + true color:
set -g default-terminal "tmux-256color"
set -ga terminal-overrides ",xterm-256color:RGB"

# 6. Bigger history:
set -g history-limit 50000

# 7. Vim-style pane navigation:
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

# 8. Vim-style copy mode:
setw -g mode-keys vi
bind -T copy-mode-vi v send -X begin-selection
bind -T copy-mode-vi y send -X copy-selection-and-cancel

# 9. Reload config:
bind r source-file ~/.tmux.conf \; display "Config reloaded"

# 10. Status bar:
set -g status-bg colour234
set -g status-fg colour137
set -g status-left "#[fg=green]#S "
set -g status-right "#[fg=cyan]%Y-%m-%d %H:%M"

Перезагрузка: Ctrl-a r (если уже в session) или из shell tmux source ~/.tmux.conf.


tmux в production: long-running jobs

Pattern для оркестрации длинного job:

# Запустить ETL в фоновой tmux session (detached):
tmux new -d -s etl_$(date +%Y%m%d) 'python /opt/etl/full_refresh.py 2>&1 | tee /tmp/etl.log'

# Опции:
# -d — start detached (не attach автоматически)
# -s name — задать имя
# 'cmd' — команда, которая выполнится в новой session

# Проверить статус:
tmux ls
# etl_20260513: 1 windows (created Mon May 13 14:30:00 2026)

# Подключиться посмотреть:
tmux attach -t etl_20260513

# Отключиться без killing job: Ctrl-b d

Это более robust, чем nohup + disown + background — потому что:

  1. Можно подключиться и посмотреть output в любой момент.
  2. Если процесс просит ввод — можно ответить (например, sudo password).
  3. Логирование в файл + интерактивный мониторинг одновременно.
NOTE

Альтернатива — systemd-run для one-shot jobs: systemd-run --unit etl-2026-05-13 python /opt/etl/full.py. systemd возьмёт ownership, можно смотреть через journalctl -u etl-2026-05-13 -f. Это production-grade, tmux — для ad-hoc и debugging.


tmux + SSH: автоматическое восстановление

# В ~/.bashrc на сервере:
if [ -z "$TMUX" ] && [ -n "$SSH_TTY" ]; then
    # Если зашли по SSH и не в tmux — auto-attach или создать
    tmux attach -t main || tmux new -s main
fi

Теперь любой SSH-логин автоматически попадает в session main. Disconnect не теряет работу.


tmux vs screen vs alternatives

Terminal multiplexers
tmuxСамый популярный, активно развивается. Кросс-платформенный, хороший дефолт. Используется в большинстве DE-команд
GNU screenLegacy, есть на любой Unix-системе включая старые AIX/Solaris. Если нужно совместимости — screen, иначе tmux лучше
zellijModern (Rust), better UX out-of-box (статусбар, mouse, иконки). Молод (2021), не везде поддержан. Альтернатива для энтузиастов

В DE-командах tmux — дефолт. Если приходишь на новое место и тебе показывают tmux session с 12 windows и Vim/htop split-screen — это норма. Освой tmux, screen учить не обязательно (можно при необходимости).


Подводные камни

1. Терминал поверх tmux поверх SSH — путаница с keybindings

Если в локальном terminal (iTerm2/Alacritty) есть tab switching на Cmd-T, а в tmux на Ctrl-b c — легко запутаться. Решение: использовать tmux только когда он нужен (production servers через SSH), а локально — нативный terminal с tab support.

2. Copy-paste между tmux и system clipboard

Стандартный tmux copy mode записывает в свой buffer, не в OS clipboard. Решение через tmux-yank plugin или tmux set -g set-clipboard on + поддержка терминала (xclip/pbcopy).

3. mouse mode иногда мешает

С set -g mouse on text selection попадает в tmux buffer, не выделяется для копирования через Cmd+C. Workaround: hold Option/Shift при выделении (терминал-dependent).

4. Different bash sessions имеют разный history

Каждый pane/window — отдельный bash process. Их history не сливается автоматически. Решение через shopt -s histappend + PROMPT_COMMAND='history -a;history -n'.


tmux + современный stack

# Запустить tmux session с готовым layout (для проекта):
#!/bin/bash
# work_session.sh
tmux new-session -d -s work
tmux send-keys -t work 'cd ~/projects/etl && nvim' C-m
tmux split-window -t work -h
tmux send-keys -t work 'cd ~/projects/etl && python -m pytest' C-m
tmux split-window -t work -v
tmux send-keys -t work 'cd ~/projects/etl && htop' C-m
tmux attach -t work

Запускаешь скрипт — session с готовым layout открывается.

Альтернатива — tmuxinator (Ruby) или tmuxp (Python) — declarative YAML configs для projects.


  • Модуль 09 (processes) — nohup/disown как альтернативы tmux для background jobs.
  • Модуль 11 (ssh) — tmux идеально работает в паре с SSH.
  • Модуль 14 (systemd) — systemd-run как production-grade alternative для one-shot jobs.
  • Урок 02 (fzf) — fzf для switching между tmux sessions.

Попробуй сам

  1. Запусти tmux, создай 2 окна, поделай в каждом что-то, переключайся через Ctrl-b 0/1.

  2. Detach (Ctrl-b d), потом tmux ls, потом tmux attach.

  3. В одном окне — top, split (Ctrl-b ”), в нижнем pane — tail -f /var/log/syslog. Переключение через Ctrl-b стрелки.

  4. Сохрани конфиг ~/.tmux.conf:

unbind C-b
set -g prefix C-a
bind C-a send-prefix
set -g mouse on
set -g base-index 1

В running session: Ctrl-b :source-file ~/.tmux.conf (или после reload tmux source ~/.tmux.conf).

  1. SSH к серверу, запусти tmux там:
ssh your-server
tmux new -s test
echo "hello"
# Ctrl-b d
exit
# Заходишь обратно:
ssh your-server
tmux attach -t test
# Видишь "hello" — session жива
  1. Long job через tmux:
tmux new -d -s long_job 'for i in {1..30}; do echo $i; sleep 10; done'
tmux ls
tmux attach -t long_job   # подключился посмотреть прогресс
# Ctrl-b d — отключился, job продолжает

Проверка знанийKnowledge check
Junior DE подключился к production server по SSH, запустил `python full_refresh.py` (длится 3 часа), закрыл laptop. Утром обнаружил: процесс убит, данные неполные. Как исправить чтобы такая ситуация не повторялась — и какие есть 3 уровня решения?
ОтветAnswer
Проблема: SSH disconnect посылает SIGHUP всем processes в сессии. Python скрипт получил SIGHUP и умер. Три уровня решения по возрастанию production-grade: **Уровень 1 — nohup**: nohup python full_refresh.py > /tmp/out.log 2>&1 & — игнорирует SIGHUP, перенаправляет stdout/stderr. Минус: интерактивный мониторинг сложен (tail -f отдельно). **Уровень 2 — tmux** (рекомендуется для ad-hoc): tmux new -d -s etl 'python full_refresh.py 2>&1 | tee /tmp/out.log' — запускает в detached session. Detach (Ctrl-b d) не убивает процесс. Можно tmux attach -t etl чтобы посмотреть live output. Disconnect — session живёт на сервере. **Уровень 3 — systemd-run** (production): systemd-run --unit=etl-2026-05-13 python /opt/etl/full_refresh.py — создаёт transient systemd unit, journald пишет логи (journalctl -u etl-2026-05-13 -f), restart policies, security boundaries. Это **правильный** способ для регулярных jobs (в комбинации с timer — модуль 15-15). Для one-shot ad-hoc — tmux обычно достаточно. Best practice DE-команд: tmux для debugging/exploration, systemd для production scheduled jobs (cron заменяется systemd timers — модуль 16).

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Какая иерархия объектов в tmux?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5