:title: Терминальные мультиплексоры
:date: 19 Oct 22
===========================
Терминальные мультиплексоры
===========================
Терминальный мультиплексор — это утилита, которая позволяет запускать
несколько сессий оболочки в рамках одной сессии и также отсоединять
собственную сессию от оболочки.
Для пояснения зачем это нужно я процитирую русскую Википедию:
Это полезно для работы с несколькими программами из командной строки, а
также для запуска программ на удаленном сервере.
Возможно звучит сложно, но всё проще чем кажется. В этой заметке я попробую
наглядно объяснить концепцию и приёмы работы с мультиплексорами терминала.
Сейчас распространено два мультиплексора терминала:
* `GNU screen `_
* `tmux `_
Рано или поздно вы с одним из них столкнётесь.
Матчасть
========
Вот основные концепции, которые использются в упомянутых утилитах.
Сессия
Непосредственно сессия мультиплексора терминала. Сессий может быть
множество, их можно создавать, закрывать, отсоединяться от них или
присоединяться, задать имя.
Окно
В любой сессии мультиплекcора есть как минимум одно окно. Если закрыть
последнее окно, то закроется вся сессия. В каждом окне запускается новая
сессия командной оболочки (Bash, Zsh и пр.).
Окон также может быть множество. К ним применимы те же действия, что и к
сессиям, кроме отсоединения.
Между окнами можно переключаться с помощью горячих клавиш.
Область экрана (или панель)
Каждое окно можно разбить на несколько областей. В каждой области будет
запущена новая сессия оболочки.
Делить окно можно по вертикали и горизонтали. Размеры областей обычно
можно отрегулировать. По умолчанию экран делится пополам.
Здесь надо отметить, что в **screen** понятия окно и область экрана
смешаны. То есть область экрана приравнивается к отдельному окну, хотя
они и отображаются на одном экране.
Итак, я подключаюсь к серверу по SSH с целью запустить там какую-то команду.
После запуска команды я намерен отключиться от сервера. При этом команда
должна продолжить выполняться. Я также должен увидеть результат её выполнения,
когда вновь подключусь к серверу.
**1.** Подключаюсь по SSH:
.. code-block:: text
localhost server
+------------+ +------------------+
| ssh_client |----->| ssh_session |
+------------+ +------------------+
(you are here)----->| shell_session(0) |
+------------------+
После успешного подключения по SSH я окажусь в сессии оболочки — **(0)**.
При этом если оборвётся SSH-сессия, то я потеряю всё что в ней было.
**2.** Как только я запущу **screen** картинка примет следующий вид:
.. code-block:: text
localhost server
+------------+ +------------------+
| ssh_client |----->| ssh_session |
+------------+ +------------------+
| shell_session(0) |
+------------------+
| screen_session |
+------------------+
(you are here)----->| shell_session(1) |
+------------------+
**3.** Для примера запущу **vim**:
.. code-block:: text
localhost server
+------------+ +------------------+
| ssh_client |----->| ssh_session |
+------------+ +------------------+
| shell_session(0) |
+------------------+
| screen_session |
+------------------+
(you are here)----->| shell_session(1) |
+------------------+
| vim |
+------------------+
**4.** Теперь я отключусь (detach) от сессии **screen**:
.. code-block:: text
localhost server
+------------+ +------------------+ +------------------+
| ssh_client |----->| ssh_session | | screen_session |
+------------+ +------------------+ +------------------+
(you are here)----->| shell_session(0) | | shell_session(1) |
+------------------+ +------------------+
| vim |
+------------------+
Сессия **screen** отсоединилась от оболочки **(0)**. При этом оболочка **(1)**
продолжает работать. Сейчас можно отключиться от SSH.
Когда я подключусь к серверу вновь, то окажусть в ситуации как на схеме 4, но
после выполнения команды **screen -r** всё вернётся к состоянию как на схеме 3
и я смогу продолжить работу в **vim**.
.. admonition:: Как набирать комбинации клавиш
Вначале набрается модификатор, например ``Ctrl+a``, затем надо отпустить
клавиши и нажать на клавишу команды, например ``?``.
screen
======
**screen** просто работает. Он минималистичен и прост в использовании.
Запуск новой сессии:
.. code-block:: text
screen [-S имя_сессии]
Подключиться к запущенной сессии:
.. code-block:: text
screen -r [имя_сессии]
=============== ============================================================
Комбинация Действие
=============== ============================================================
Ctrl+a ? Показать справку
Ctrl+a : Открыть приглашение для ввода команд screen
Ctrl+a " Список окон
Ctrl+a 0 Открыть окно номер 0
Ctrl+a A Переименовать текущее окно
Ctrl+a a Отправить комбинацию Ctrl+a в текущее окно
Ctrl+a c Создать новое окно (с оболочкой)
Ctrl+a S Разделить текущую область по горизонтали
Ctrl+a | Разделить текущую область по вертикали
Ctrl+a tab Перевести фокус ввода на следующую область
Ctrl+a Ctrl+a Переключиться между текущей и предыдущей областью
Ctrl+a Esc Перейти в режим копирования (используйте Enter для выделения
текста). Также скроллинг терминала.
Ctrl+a ] Вставить текст
Ctrl+a Q Закрыть все окна, кроме текущего
Ctrl+a X Закрыть текущую область
Ctrl+a d Отсоединиться от текущей сессии
=============== ============================================================
При разделении экрана на области появится новая пустая область. Нужно
переключить на неё фокус и запустить новое окно с оболочкой ``Ctrl+a`` ``c``.
Конфигурация **screen** хранится в файле **~/.screenrc**. Я для себя написал
совсем простой конфиг, который тем не менее показывает всё что действительно
нужно.
.. code-block:: unixconfig
startup_message off
hardstatus alwayslastline
hardstatus string '%S: %-w%>(%n %t)%{-}%+w%<'
.. image:: https://i.nxhs.cloud/Swl.png
:alt: Terminal with screen
Материалы по **screen**:
* `GNU screen usage `_
* `GNU screen - ArchWiki `_
tmux
====
**tmux** — это более новороченное решение. Он умеет почти всё то же что
**screen** + имеет дополнительные фичи вроде управления мышью.
Запустить новую сессию:
.. code-block:: text
tmux [new -s имя_сессии]
Подключиться к сессии:
.. code-block:: text
tmux a [-t имя_сессии]
=============== ============================================================
Комбинация Действие
=============== ============================================================
Ctrl+b c Создать новое окно
Ctrl+b , Переименовать окно
Ctrl+b w Список окон
Ctrl+b " Разделить текущую область по горизотали
ctrl+b % Разделить текущую область по вертикали
Ctrl+b x Закрыть текущую панель
Ctrl+b [ Перейти в режим копирования текста + скроллинг
Ctrl+b d Отсоединиться от сессии
=============== ============================================================
Мой **~/.tmux.conf**:
.. code-block:: unixconfig
set -g mouse on
set -g history-limit 5000
# vim style controls
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
bind -r H resize-pane -L 10
bind -r J resize-pane -D 10
bind -r K resize-pane -U 10
bind -r L resize-pane -R 10
# Copy / paste
bind b list-buffers
bind B show-buffer
bind P paste-buffer
bind-key -T copy-mode-vi v send-keys -X begin-selection
bind-key -T copy-mode-vi y send-keys -X copy-selection
bind-key -T copy-mode-vi r send-keys -X rectangle-toggle
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel \
"xclip -i -f -selection primary | xclip -i -selection clipboard"