Ситуация, в которой терминала не хватает
Вы запускаете в терминале долгую команду. Например, она опрашивает что-то раз в пару секунд и печатает результат на экран, а вы в это время хотите открыть второй терминал и посмотреть файл проекта. Никакой проблемы: в Ubuntu можно открыть новое окно терминала или новую вкладку, и работать дальше. Но теперь представьте, что соединение с машиной идёт по SSH. Вы запустили долгую операцию на сервере, и тут сеть моргнула. После обрыва сеанса запущенный процесс может завершиться вместе с ним. Ещё обиднее, когда вы сами случайно закрыли окно, не подумав.
Хочется, чтобы работа в терминале не была привязана к конкретному окну. Чтобы можно было запустить команду, отключиться от неё, заняться другим делом, а потом вернуться и увидеть тот же экран с выводом. Именно эту задачу решает tmux — терминальный мультиплексор. Он запускается как обычная программа внутри терминала, но берёт на себя роль посредника между окном терминала и запускаемыми командами. Окно можно закрыть, а команды продолжат работать внутри tmux. Когда мы снова откроем терминал и подключимся к tmux, мы увидим тот же самый сеанс: тот же вывод, те же процессы, то же состояние.
Слово tmux — сокращение от terminal multiplexer. Программа есть в репозиториях Ubuntu, и для урока она понадобится установленной.
Проверяем установку
Сначала проверим, установлен ли tmux:
tmux -V
Опция -V — это сокращение от version, и заглавная буква здесь важна: строчная -v у tmux имеет другое назначение. Если tmux есть, мы увидим что-то похожее:
tmux 3.4
Номер версии может отличаться. Если же команда не найдена, установим пакет:
sudo apt update
sudo apt install tmux
После установки снова проверим версию. Никакой начальной настройки для этого урока не требуется. Мы работаем с tmux как с чистой программой, без конфигурационного файла.
Три слоя tmux: клиент, сервер, сессия
У tmux есть важная особенность, которую полезно понять с самого начала. Программа не просто открывает новое окно. Она запускает собственный фоновый процесс — сервер tmux. Именно сервер хранит всё, что происходит внутри: открытые сессии, окна, запущенные команды и их вывод. Клиент — это то, что мы видим в терминале. Когда мы вводим команду tmux, запускается клиент, который подключается к серверу и показывает нам его состояние. Если сервера ещё нет, первая команда tmux его создаст.
Внутри сервера живёт одна или несколько сессий. Сессия — это наш рабочий сеанс, у которого есть имя. В нём могут быть окна и панели, но на этом уроке мы ограничимся одной сессией и одним окном, чтобы не перегружать знакомство. Важно различать эти три слова: внутри терминала работает клиент tmux; фоновый процесс, который держит всё состояние, — сервер; именованный рабочий сеанс внутри сервера — сессия.
Когда мы закроем окно терминала, клиент исчезнет, но сервер и сессия останутся. Позже мы откроем новый терминал, запустим клиент заново и подключимся к той же сессии.
Создаём сессию, не задев чужую
Прежде чем создавать сессию, проверим, какие сессии tmux уже запущены:
tmux ls
Команда ls здесь — сокращение от list-sessions. Если сервер только что установлен и мы его ни разу не запускали, вывод будет такой:
no server running on /tmp/tmux-1000/default
Путь может отличаться, но смысл один: сервера нет, значит, и сессий нет. Если же в выводе будут перечислены сессии, не нужно создавать новую с тем же именем и тем более не нужно удалять чужие. Обычно tmux использует отдельный сервер для каждого пользователя. Но в той же учётной записи могут идти другие работы, поэтому существующие сессии не трогаем. В учебной среде скорее всего вывод окажется пустым или сообщит об отсутствии сервера, и мы сможем спокойно двигаться дальше.
Создадим нашу сессию с именем course-work:
tmux new -s course-work
Разберём опции. new — это сокращение от new-session, то есть создать новую сессию. Опция -s задаёт имя сессии, от слова session. Аргумент после неё — само имя. Имя нужно выбирать осмысленно, чтобы потом легко было понять, где что лежит. У нас будет рабочая сессия курса, поэтому course-work.
Сразу после этой команды вид терминала изменится: появится зелёная полоса внизу, а командная строка останется прежней. Полоса — это признак того, что мы теперь видим не просто терминал, а клиент tmux, подключённый к нашей новой сессии. Внутри мы работаем с обычной оболочкой Bash: те же команды, те же пути, то же окружение.
Нам нужно убедиться, что сессия действительно создана и мы можем в ней работать, но сделать это нужно, не выходя из неё. Запомним простое правило: мы пока внутри tmux, и обычные команды выполняет оболочка. Специальные команды tmux мы будем вызывать через префикс, но об этом чуть ниже.
Первая команда внутри tmux
Внутри сессии посмотрим служебную переменную tmux:
echo "$TMUX"
Это не команда tmux, а обычное обращение к переменной окружения. tmux выставляет её для каждой сессии. Вывод содержит путь к сокету, PID сервера tmux и числовой идентификатор сессии, например:
/tmp/tmux-1000/default,12345,0
Путь и числа у вас будут другими. Важно, что переменная не пуста: это значит, что оболочка действительно работает внутри tmux. В обычном терминале переменная TMUX не установлена, и команда выведет пустую строку.
Теперь запустим долгую команду. Она не делает ничего вредного: просто печатает текущее время каждые две секунды, пока мы её не остановим. Выглядит она так:
while true; do date -Is; sleep 2; done
Здесь while true; do начинает бесконечный цикл. Команда date -Is выводит текущую дату и время в формате ISO 8601, той же командой мы пользовались в уроках о расписаниях. sleep 2 приостанавливает цикл на две секунды. done закрывает цикл. В итоге на экран каждые две секунды добавляется новая строка с временем, и цикл сам не закончится — его нужно будет остановить вручную.
Строки начнут появляться одна за другой. Так и должно быть. Команда выполняется прямо сейчас, и экран занят ею. Мы больше не можем вводить другие команды в этом окне: оболочка занята циклом. Но нам и не нужно ничего вводить — сейчас главное увидеть, что сессия работает.
Отключаемся от сессии
Пока цикл продолжает печатать время, отключимся от сессии. Для этого используется особое сочетание клавиш, которое называется префикс. В tmux по умолчанию префикс — это Ctrl+b. Работает он не так, как обычные сочетания вроде Ctrl+C. Сначала нужно нажать Ctrl+b и отпустить, а затем нажать следующую клавишу — саму команду. Клавиши не нужно держать одновременно.
Для отключения от сессии после префикса нажимается латинская буква d, от слова detach — отсоединить. Итак, полная последовательность: нажать и отпустить Ctrl+b, затем нажать d. Никакого подтверждения не будет. Экран вернётся к обычному терминалу, а цикл останется работать внутри tmux. Внешне это выглядит так, будто мы вышли из программы, но это не так: мы оставили сессию работать в фоне и просто закрыли клиент.
Важно не путать detach с остановкой. Цикл продолжит печатать время, но мы этого не видим. tmux хранит текущий экран и ограниченную историю строк. После возвращения мы увидим новый вывод, но tmux не заменяет сохранение полного журнала в файл.
Смотрим на сессию со стороны
Теперь, когда мы снова в обычном терминале, проверим список сессий:
tmux ls
Вывод станет другим. Теперь мы увидим нашу сессию:
course-work: 1 windows (created ...)
Точная дата и время будут вашими. Смысл вывода: у нас есть одна сессия с именем course-work, и в ней одно окно. Сервер tmux при этом продолжает работать в фоне. Мы можем закрыть окно терминала, открыть новое, и сессия останется. Мы даже можем просто продолжить в том же окне — это не имеет значения. Главное, что мы отсоединились, а не уничтожили сессию.
Возвращаемся и останавливаем цикл
Вернёмся внутрь:
tmux attach -t course-work
Опция -t сокращает слово target, цель. Она указывает, к какой сессии подключаться. Можно было написать полную форму attach-session, но attach быстрее. После этой команды снова появится зелёная полоса, а на экране мы увидим уже накопившиеся строки с временем. Их может быть много — цикл не останавливался всё то время, пока нас не было. Это и есть главное свойство tmux: процесс не зависел от открытого терминала.
Остановим цикл так же, как остановили бы любую команду в обычной оболочке: нажмём Ctrl+C. Цикл прервётся, оболочка снова станет доступна, и можно вводить следующие команды. Останавливать нужно именно сам цикл, а не tmux. Убивать сервер tmux для этого не требуется и нежелательно: наша цель — оставить сессию живой для следующего урока.
После Ctrl+C командная строка вернётся. Проверим, что мы всё ещё внутри tmux:
echo "$TMUX"
Переменная должна быть на месте. Это ожидаемо: мы не выходили из сессии, а только остановили одну команду внутри неё.
Оставляем сессию для следующего урока
Теперь нам нужно завершить урок, но сохранить сессию для продолжения. Отключимся тем же способом, что и раньше: Ctrl+b, затем d. Мы снова окажемся в обычном терминале. Проверим список сессий:
tmux ls
Сессия course-work всё ещё на месте. Внутри неё теперь работает обычная оболочка Bash, готовая принимать команды. В следующем уроке мы подключимся к этой же сессии и разберём, как создавать окна и панели.
На этом первый урок с tmux закончен. Мы не удаляем сервер и не убиваем сессию. Не останавливайте весь сервер tmux ради одной учебной команды: это затронуло бы остальные сессии этой учётной записи. Учебная среда должна остаться в том состоянии, к которому мы придём в конце каждого урока, чтобы следующее занятие начиналось с осмысленного продолжения.
tmux решает задачу отвязки работы в терминале от конкретного окна. Он состоит из трёх частей: клиента, который показывает нам экран, сервера, который хранит всё состояние, и сессии — именованного рабочего сеанса внутри сервера. Когда мы закрываем окно терминала, клиент исчезает, но сервер и сессия продолжают работать. Мы создали сессию course-work командой tmux new -s course-work, предварительно проверив через tmux ls, что имя свободно.
Внутри сессии мы запустили бесконечный цикл while true; do date -Is; sleep 2; done, который печатал время каждые две секунды. Пока он работал, мы отключились от сессии сочетанием Ctrl+b и затем d. Цикл продолжил выполняться. Вернувшись через tmux attach -t course-work, мы увидели накопившийся вывод и остановили команду обычным Ctrl+C. После этого сессия осталась работать с обычной оболочкой. В следующем уроке мы подключимся к ней снова и научимся делить экран на окна и панели.
Мы разобрали, из чего состоит tmux и как устроены сессии: клиент показывает экран, сервер держит состояние, а сессия хранит рабочий сеанс. Теперь проверим это на двух задачах. Сначала разберём ситуацию с отсоединением и остановкой среды, а потом вы сами пройдёте полный круг: создадите свою сессию, отключитесь, вернётесь и оставите её живой.
Detach, завершение и остановка WSL
Прежде чем работать руками, стоит убедиться, что вы различаете отсоединение и завершение. Это два похожих внешне действия с очень разными последствиями для сессии.
В учебной среде WSL в терминале открыта сессия tmux с именем course-work. Внутри неё запущен бесконечный цикл, который печатает время каждые две секунды. Ученик нажал и отпустил Ctrl+b, а затем нажал d. Экран вернулся к обычному терминалу. Команда tmux ls показывает: course-work: 1 windows (created ...). После этого ученик закрыл окно терминала. Какие утверждения верны? Выберите все верные.
Своя сессия: от создания до возврата
Теперь пройдём весь путь самостоятельно, но не в сессии course-work, а в своей. Это позволит потренироваться и не задеть состояние, которое понадобится на следующем занятии.
В учебной среде WSL уже работает сервер tmux, и в нём есть сессия course-work, которую мы создавали на уроке. Трогать её нельзя: она останется для следующего занятия. Также допустим, что в этой же учётной записи могли бы быть и другие сессии, поэтому ни одну чужую сессию мы не удаляем и не переименовываем.
Придумайте своё новое имя для учебной сессии, которого ещё нет (не course-work и не занятое другими). Опишите последовательность команд и нажатий, которая выполняет следующее:
- сначала проверяет, какие сессии tmux уже запущены;
- создаёт вашу новую сессию с вашим именем;
- внутри неё запускает команду, которая печатает строку раз в пару секунд и сама не заканчивается;
- отключается от сессии, оставив её и процесс работать;
- из обычного терминала убеждается, что ваша сессия есть в списке;
- возвращается в неё;
- останавливает бесконечный процесс, не завершая саму сессию;
- оставляет сессию живой, чтобы к ней можно было вернуться позже.
Сервер tmux убивать нельзя, а также нельзя завершать или трогать сессию course-work и любые другие чужие сессии. Укажите команды так, как вводили бы их в терминале, и коротко поясните, что ожидаете увидеть на каждом шаге. Начинайте из обычной оболочки вне tmux; если $TMUX непустая, сначала отсоединитесь от текущего клиента, не завершая его сессию.