Привет, Хабр!

Бывало, открываешь десяток терминалов, чтобы мониторить систему: в одном htop, в другом делаешь tail логов, в третьем запускаешь отладку. Через пару минут такой работы голова идет кругом от мельтешащих окон. Для того, чтобы как‑то разобраться с этим, помогут терминальные мультиплексоры, старый добрый GNU Screen и его более крутой товарищ tmux.

Быстрый экскурс

Если кратко, и tmux, и GNU Screen позволяют в одном терминале запускать несколько «окон» (на самом деле псевдотерминалов) и свободно между ними переключаться.

Можно отсоединяться (detach) от такой сессии и потом снова подключаться (attach), даже по SSH, все запущенные процессы продолжают работать в фоне.

Tmux считается более современным и удобным, у него богатый функционал, настраиваемый интерфейс, да и скриптовать его проще. Screen тоже умеет в автоматизацию, но функционала там поменьше. Я буду в основном говорить про tmux, но замечу кое‑где и про Screen для полноты картины.

Создаем сессию через командную строку

Начнем с азов: как запустить новую tmux‑сессию не вручную через интерактивный интерфейс, а прямо командой. Обычно мы пишем в терминале tmux, и он нас перекидывает внутрь новой сессии. Но для скриптов такой вариант не подойдет, скрипт зависнет, ожидая, пока вы закончите работу в tmux. Нужно запускать сессию в фоне.

Для этого у команды tmux new-session есть специальный флаг:

tmux new-session -d -s mysession

Эта команда запустит новую сессию tmux под именем mysession и сразу ее отсоединит. Ключ -d (--detach) и делает все что нужно, tmux не захватывает ваш текущий терминал. Скрипт пойдет выполняться дальше, а сессия будет жить сама по себе в фоне.

Флаг -s mysession задает имя сессии. Вы можете назвать ее как угодно. Если имя не указать, tmux придумает что‑то по умолчанию (часто просто номер), но лучше дать осмысленное.

После выполнения tmux new-session -d -s mysession у нас есть фоновая tmux‑сессия. В ней, по дефолту, создано одно окно с шеллом (скорее всего, bash) и оно ждет ваших команд. Как подать команду в эту свежесозданную сессию? Есть несколько подходов:

  • Запустить нужную программу сразу при создании сессии (tmux позволяет указать команду в кавычках прямо в команде new-session).

  • Или запустить команду позже, отправив текст на ввод с помощью tmux send-keys.

Попробуем оба варианта.

Запуск команды при создании сессии

Самый простой способ при создании новой сессии сразу сказать tmux, что в первом окне надо выполнить конкретную программу. Делается это так, после параметров указывается команда в кавычках:

tmux new-session -d -s mysession 'htop'

Запускаем сессию mysession и сразу в первом окне этой сессии выполняем утилиту htop. Tmux создаст окно, запустит там htop и оставит его работать.

Если сейчас подключиться к сессии командой tmux attach -t mysession, мы прямо увидим интерфейс htop. Однако подождите, не будем пока аттачиться, мы же еще хотим открыть другие окна и панели, все автоматом!

Добавляем окна и панели

Одна tmux‑сессия может содержать несколько окон, а окно делиться на панели. Нам по задаче нужно три параллельных экрана: htop, логи и просто шелл. В терминах tmux это либо три окна, либо одно окно с тремя панелями. В примере явно указано «3 окна», значит сделаем три отдельных окна в рамках одной сессии.

У нас уже есть одно окно (с htop). Создадим второе для логов. Используем команду:

tmux new-window -t mysession: -n logs

Разберем: new-window, команда tmux для создания нового окна в существующей сессии. Ключ -t mysession: говорит создать окно в сессии mysession. Двоеточие тут отделяет имя сессии от имени или номера окна (который мы не указали, поэтому tmux присвоит следующий номер). Флаг -n logs задает имя окна (оно же будет отображаться в статусной строке tmux).

По дефолту новое окно откроется с вашим shell и остановится на приглашении командной строки. Нам же нужно, чтобы там сразу начали отображаться логи. Можно сразу запустить tail -f при создании окна, аналогично тому, как мы сделали с htop:

tmux new-window -t mysession: -n logs 'tail -f /var/log/syslog'

Предположим, в качестве примера хочется смотреть системный лог /var/log/syslog. Вы подставьте сюда свой путь или команду, если нужно что‑то специфическое.

Осталось третье окно, обычный шелл. Его можно создать тоже командой:

tmux new-window -t mysession: -n shell

Здесь не передаем команду в кавычках, поэтому tmux просто откроет пустой bash с промптом. Окно называем «shell» для ясности, хотя можно не именовать, тогда оно получит название по умолчанию (обычно на основе запущенной программы, в данном случае отобразилось бы «bash»).

Итак, в скрипте выполнили три команды: new-session и два раза new-window. Теперь наша сессия mysession уже имеет три окна. Причем:

  • Окно 0 (первое) запущено с htop.

  • Окно 1 (второе) запущено с tail -f /var/log/syslog и отображает лог.

  • Окно 2 (третье) — просто ждет команды в шелле.

Нумерация окон начинается с 0 в tmux, имейте в виду. Но имена задали понятные, и можно дальше оперировать именами, либо номерами, как удобнее.

Отправляем команды внутрь tmux

Мы научились стартовать окна сразу с нужными программами. А что если нужно в уже существующую панель или окно отправить команду? Например, вы хотите разбить окно на две панели и во вторую панель передать какую‑то команду уже после создания. Тут пригодятся tmux split-window и tmux send-keys.

split-window делит текущее окно на две панели (по горизонтали или вертикали, как скажете). Но когда мы работаем из скрипта, нужно указать явно, какое окно делить. По умолчанию, если просто вызвать tmux split-window, tmux будет считать текущим последнее активное окно/панель. В скрипте это может быть неочевидно. Лучше явно задать через -t.

Предположим, вместо отдельного окна для логов я захотел сделать панель рядом с htop (в одном окне). Можно так и сделать:

tmux new-session -d -s mysession 'htop'
tmux split-window -t mysession:0 -v 'tail -f /var/log/syslog'

Здесь флаг -t mysession:0 указывает: «разделить окно номер 0 (наш htop)». -v означает вертикальный сплит (панели одна под другой; есть еще -h для горизонтального разделения). И сразу после этих флагов я передал команду 'tail -f /var/log/syslog' — tmux запустит ее во второй панели. В итоге окно 0 разделилось на две панели: верхняя с htop, нижняя с логом. Оба вида информации на одном экране.

Но вернемся к send-keys. Эта команда нужна, если вы хотите послать символьный ввод в уже запущенную программу или просто в пустой шелл. Она буквально имитирует нажатие клавиш в целевой панели. Например, можно отправить команду в панель, где сейчас открыт bash:

tmux send-keys -t mysession:2 'ls -la' C-m

Здесь -t mysession:2 означает «послать ввод в окно 2 сессии mysession» (в нашем случае окно 2 — это тот самый пустой shell). Далее в кавычках идет текст ls -la, а после кавычек указано C-m. Комбинация C-m, способ послать «Enter» (Carriage Return) в tmux. То есть мы отсылаем строку ls -la и затем нажатие Enter. В результате в том окне 2 выполнится ls -la и мы получим список файлов прямо там.

Фокус в том, что tmux send-keys не выводит результат вам напрямую. Он просто нажимает клавиши в той сессии. Результат команды останется в окне tmux. Потом, когда вы подключитесь, вы увидите, что в окне 2 уже выполнена команда ls -la и выведен список файлов.

send-keys удобно использовать, чтобы подготовить окружение: например, открыть несколько панелей и в каждой уже запустить нужные утилиты, скрипты или команды. Фактически вы программируете последовательность действий, которую обычно руками бы делали после открытия tmux.

В -t можно указывать не только окно, но и конкретную панель, если их несколько. Синтаксис вида session:window.pane. Например, mysession:0.1 первая панель окна 0. Нумерация панелей идет с 0. В простых случаях хватает указать окно, тогда если там одна панель (0), команды пойдут туда.

Подключаемся к готовой сессии

После того как скрипт настроил все окна, хорошо бы увидеть результат своими глазами. Тут помогает tmux attach. Чтобы не мешать работе скрипта, мы все сессии запускали с -d, то есть без аттача. Теперь можно подключиться вручную:

tmux attach -t mysession

Или коротко tmux a -t mysession. Вы окажетесь внутри tmux, увидите первое окно/панель. Переключаться между окнами Ctrl+B, а затем номер окна (0, 1, 2) или Ctrl+B N/Ctrl+B P (Next/Previous). Выйти из tmux, не убивая сессию, Ctrl+B D (detach). Сессия при этом продолжит работать в фоне.

Если запуск происходил в скрипте, можно, в принципе, сделать так, чтобы скрипт сам подключил вас, выполнив в конце tmux attach. Но есть нюанс, если скрипт был запущен по SSH и выполнил attach, он может захватить ваше подключение.

Запускаем мониторинг одним скриптом

Соберем все вместе. Приведу пример простого Bash‑скрипта, который поднимает описанную выше сессию с тремя окнами:

#!/bin/bash
SESSION="workenv"

# 1. Создаем новую tmux-сессию в фоне, окно 0 с htop
tmux new-session -d -s "$SESSION" -n htop 'htop'

# 2. Добавляем окно с логами (окно 1)
tmux new-window -t "$SESSION": -n logs 'tail -f /var/log/syslog'

# 3. Добавляем окно с шеллом (окно 2)
tmux new-window -t "$SESSION": -n shell

# 4. Отправляем команду в окно shell, чисто для примера (выполнит ls)
tmux send-keys -t "$SESSION":2 'ls -la' C-m

# 5. Подключаемся к сессии (уберите эту строчку, если не хотите автоматом аттачиться)
tmux attach -t "$SESSION"

Вот такой сценарий. Комментариями обозначил каждый шаг. Шаг 4 необязательный, он просто демонстрирует send-keys. В жизни скорее всего вы либо сразу запускаете процессы при создании окон, либо заходите внутрь tmux и вводите команды руками.

Обратите внимание на кавычки и переменные: "${SESSION}":2 разворачивается в mysession:2. В bash лучше брать переменные в кавычки на случай пробелов (в именах сессий обычно нет пробелов, но это хорошая привычка).

Этот скрипт можно сохранить, например, как start_env.sh, дать ему права на выполнение (chmod +x start_env.sh) и запускать, когда нужно настроить такое окружение.

При запуске скрипт быстро пролетит и либо вернет вас в шелл (если вы не делали attach внутри), либо откроет tmux‑сессию. Если вы включили авто‑attach (шаг 5), то скрипт фактически передаст вам управление внутри tmux. По выходу из tmux (detach или закрытие сессии) вы вернетесь туда, откуда скрипт запускали.

Кратко о GNU Screen

Не могу не упомянуть несколько слов о GNU Screen, ведь он был популярен задолго до tmux. Если по каким‑то причинам вам нужен именно Screen, знайте: у него тоже есть похожие возможности.

Например, команда:

screen -dmS session_name htop

сделает примерно то же, что и tmux new-session -d ... 'htop' — запустит screen‑сессию с именем session_name и программой htop внутри, отсоединившись сразу (-d -m означает «detach и запустить»).

Создать новое окно (в терминологии Screen новое окно, по сути как tmux‑окно) можно так:

screen -S session_name -X screen tail -f /var/log/syslog

Отправили команду уже в запущенную сессию (‑S выбирает сессию по имени). Ключ -X говорит Screen выполнить последующую команду управления. Команда screen (в контексте ‑X) добавляет новое окно внутри сессии. В итоге появится второе окно с tail.

Аналог send-keys в Screen — команда stuff. Она посылает текст в выбранное окно:

screen -S session_name -p 0 -X stuff "ls -la\n"

Здесь -p 0 выбирает окно 0, и мы шлем туда строку ls -la + перевод строки (\n). Учтите: если запускать Screen в фоне без команды, сразу после -dmS, то по умолчанию не будет активного окна для stuff, и команда может никуда не отправиться. Поэтому либо запускайте сессию с каким‑то процессом (например, bash), либо сперва создайте окно через screen -X screen.

В целом Screen скриптовать можно, но синтаксис, как видите, более громоздкий. И функциональности меньше (например, делить окно на панели Screen не умеет, только отдельные окна). В новых проектах tmux почти полностью его вытеснил. Однако хорошо понимать оба инструмента: вдруг придется работать на сервере, где доступен только Screen.

Управление сессиями: статус, attach, kill

Напоследок полезные команды для управления tmux‑сессиями через CLI:

  • tmux ls (или tmux list-sessions) показывает список запущенных tmux‑сессий. Полезно в скрипте, чтобы проверить, не запущена ли уже наша сессия, и не плодить дублей.

  • tmux attach -t <name>подключиться к существующей сессии. Если вы в скрипте не делаете авто‑attach, можно просто вывести пользователю сообщение, мол «сессия запущена, подключитесь командой tmux attach -t mysession„.“»

  • tmux detach -s <name> принудительно отсоединить сессию <name> от всех клиентов. Бывает нужно в автоматизации, если, скажем, пользователь забыл отсоединиться, а скрипт должен продолжить что‑то делать. Если же клиентов нет, команда вернет ошибку «no client found». Честно говоря, без особой надобности я ее не использую.

  • tmux kill-session -t <name> завершить указанную сессию и убить все ее окна/процессы. Аккуратнее — может быть полезно в скриптах «чистки» или перезапуска окружения, когда перед запуском новой сессии нужно убрать старую, если вдруг висит.

У Screen аналоги следующие: screen -ls, screen -r <name> (reattach к сессии), screen -S <name> -X quit (выйти из сессии).


Заключение

Попробуйте написать свой скрипт под свои задачи, например, открывать сразу сессию для разработки: в одном окне редактор, в другом сервер на npm start, в третьем мониторинг логов. Фантазия не ограничена, а скрипты терпеливо выполнят любую задачу.

Удачной автоматизации и приятных случайностей!

Готовы к серьезному обучению по Linux? Пройдите вступительный тест на оценку знаний.
Готовы к серьезному обучению по Linux? Пройдите вступительный тест на оценку знаний.

Tmux и Screen дают удобный поверхностный контроль, но настоящая эффективность приходит, когда сама система предсказуемо ведёт себя под нагрузкой. Если хочется глубже понять устройство Linux-дистрибутивов, сетевые стековые тонкости и приёмы повышения производительности, это можно системно отработать на продвинутом курсе по Linux-администрированию.

Для знакомства с форматом обучения и экспертами приходите на бесплатные демо-уроки:

  • 9 декабря в 20:00. Основы LVM: гибкое управление дисковым пространством в Linux. Записаться

  • 18 декабря в 20:00. Docker в продакшене: сборка образов, безопасность и CI/CD. Записаться

Комментарии (0)