254 lines
12 KiB
ReStructuredText
254 lines
12 KiB
ReStructuredText
|
:title: Терминальные мультиплексоры
|
|||
|
:date: 19 Oct 22
|
|||
|
|
|||
|
===========================
|
|||
|
Терминальные мультиплексоры
|
|||
|
===========================
|
|||
|
|
|||
|
Терминальный мультиплексор — это утилита, которая позволяет запускать
|
|||
|
несколько сессий оболочки в рамках одной сессии и также отсоединять
|
|||
|
собственную сессию от оболочки.
|
|||
|
|
|||
|
Для пояснения зачем это нужно я процитирую русскую Википедию:
|
|||
|
|
|||
|
Это полезно для работы с несколькими программами из командной строки, а
|
|||
|
также для запуска программ на удаленном сервере.
|
|||
|
|
|||
|
Возможно звучит сложно, но всё проще чем кажется. В этой заметке я попробую
|
|||
|
наглядно объяснить концепцию и приёмы работы с мультиплексорами терминала.
|
|||
|
|
|||
|
Сейчас распространено два мультиплексора терминала:
|
|||
|
|
|||
|
* `GNU screen <https://www.gnu.org/software/screen/>`_
|
|||
|
* `tmux <https://github.com/tmux/tmux/wiki>`_
|
|||
|
|
|||
|
Рано или поздно вы с одним из них столкнётесь.
|
|||
|
|
|||
|
Матчасть
|
|||
|
========
|
|||
|
|
|||
|
Вот основные концепции, которые использются в упомянутых утилитах.
|
|||
|
|
|||
|
Сессия
|
|||
|
Непосредственно сессия мультиплексора терминала. Сессий может быть
|
|||
|
множество, их можно создавать, закрывать, отсоединяться от них или
|
|||
|
присоединяться, задать имя.
|
|||
|
|
|||
|
Окно
|
|||
|
В любой сессии мультиплек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 <http://gnuscreen.org/>`_
|
|||
|
* `GNU screen - ArchWiki <https://wiki.archlinux.org/title/GNU_Screen>`_
|
|||
|
|
|||
|
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"
|