ZaLinux.ru

Как закрыть терминал без убийства запущенной в нём команды

Иногда нужно «отвязать» программа от окна терминала, в котором она запущена. Например, вы подключились к удалённому серверу по SSH, запустили задачу, которая не является демоном, но выполнение которой требует большого времени (может быть дни и месяцы). Если вы закроете терминал или просто оборвёте SSH сессию, то запущенная программа попросту прекратит свою работу.

Ещё один пример ситуации, когда это может понадобиться, вы работаете с безголовым сервером (без графического окружения рабочего стола) и по этой причине не можете открыть несколько терминальных окон. Поэтому вы хотите перевести программу в фон, чтобы продолжить работу с терминалом. 

В этой статье описаны варианты, как закрыть терминал без остановки запущенной в нём программы.

Для этого есть два решения:

nohup команда &

или

команда &
disown

Давайте разберёмся, а в чём различия между

nohup команда

и

команда &

и

команда &
disown

Давайте для начала взглянем, что происходит, когда команда запускается из интерактивной оболочки (подключённой к терминалу) без & (и без какого либо перенаправления). Поэтому давайте предположим, что вы напечатали просто foo (в качестве примера команды), тогда:

  • Создаётся процесс foo.
  • Процесс наследует stdin (стандартный ввод), stdout (стандартный вывод), и stderr  (стандартный вывод ошибок) из оболочки. Следовательно, он также подключён к тому же терминалу.
  • Если оболочка получает SIGHUP (сигнал, посылаемый процессу для уведомления о потере соединения с управляющим терминалом пользователя), она также отправляет SIGHUP процессу (что обычно приводит к завершению процесса).
  • В противном случае оболочка ожидает (является заблокированной) пока процесс завершиться.

Теперь давайте посмотрим, что происходит, когда мы переводим процесс в фон, это делается набором foo &:

  • Создаётся запущенный процесс foo.
  • Процесс наследует stdout/stderr из оболочки (поэтому он всё ещё пишет в терминал).
  • Процесс, в принципе, также наследует stdin, но как только он пытается читать из stdin, он приостанавливается.
  • Он помещается в список фоновых задач, которыми управляет оболочка, что в частности означает:

    • Он выводиться по jobs и к нему можно получить доступ используя %n (где n – это номер задачи).
    • Его можно перевести на задачу переднего плана, используя fg, в этом случае он продолжится, будто бы вы не использовали с ним & (и если раньше он останавливался, при попытке читать стандартный ввод, теперь он может работать с чтением стандартного ввода из терминала).
    • Если оболочка получает SIGHUP, она также отправляет SIGHUP процессу. В зависимости от оболочки и возможных включённых опций оболочки при завершении оболочки она также будет отправлять процессу SIGHUP.

Теперь disown удаляет задачу из списка задач оболочки, следовательно все приведённые выше подпункты больше не применяются (включая отправку оболочкой процессу сигнала SIGHUPl). Тем не менее, помните, что он всё ещё подключён к терминалу, поэтому если терминал разрушен (что может случиться если это был pty, как те, которые создаются xtermor или ssh, и контролирующая программа завершена закрытием xterm или закрытием SSH-подключения), программа потерпит неудачу, как только она почитается прочитать из стандартного ввода или записать в стандартный вывод.

Что оделает nohup, с одной стороны, она активно отделяет процесс от терминала:

  • Она закрывает стандартный ввод (программа будет неспособна читать любой стандартный ввод, даже если она запущена на переднем плане. Она не закрывается если не получает сообщение об ошибке или EOF).
  • Она перенаправляет стандартный вывод и стандартный вывод ошибок в файл nohup.out, поэтому программа не потерпит неудачу во время записи в стандартный вывод если терминал потерпит неудачу, то чтобы процесс не писал, это не будет потеряно.
  • Она не даёт процессу получить SIGHUP (отсюда и её имя).

Помните, что nohup не удаляет процесс из контроля задач оболочки и также не переводит его в фон (но поскольку задача nohup на переднем плане практически бесполезно, то обычно она запускается с использованием &). Например, в отличие от disown, оболочка всё ещё будет говорит вам, когда задача nohup завершена (конечно, если оболочка не закрылась раньше этого).

Итак подытожим:

  • & переводит задачу в фон, это приводит к блокировке попыток читать стандартный ввод и делает так, что оболочка не ждёт завершения задачи.
  • disown удаляет процесс из контроля задач оболочки, но всё ещё оставляет её связанной с терминалом. Одним из результатов этого является то, что оболочка не отправит SIGHUP. Очевидно, что это может быть применимо только к фоновым задачам, поскольку вы не можете ввести это когда запущена работа на переднем плане.
  • nohup отсоединяет процесс от терминала, перенаправляет его вывод в nohup.out и предохраняет его от SIGHUP. Одним из эффектов (в честь которого и названа команда) является то, что процесс не получит любой отправленный NOHUP. Он абсолютно независим от контроля задач и может, в принципе, использоваться для задач на переднем плане (хотя это не особо полезно).

Если использовать вместе все три disown, nohup и &, то процесс будет запущен в фоне, удалён из контроля задач оболочки и эффективно отключён от терминала.

nohup выполняет КОМАНДУ игнорируя сигналы обрыва терминальной линии.

Возможные опции nohup:

      --help     показать эту справку и выйти
      --version  показать информацию о версии и выйти

Если стандартный ввод является терминалом, то он берётся из нечитаемого файла.

Если стандартный вывод является терминалом, то вывод добавляется в «nohup.out», если возможно, иначе в «$HOME/nohup.out».

Если стандартный поток ошибок является терминалом, то он перенаправляет в стандартный вывод. Чтобы записать вывод в ФАЙЛ, используйте «nohup КОМАНДА > ФАЙЛ».

ЗАМЕЧАНИЕ: ваша оболочка может предоставлять свою версию nohup, которая обычно перекрывает версию, описанную здесь. Пожалуйста, обращайтесь к документации по вашей оболочке, чтобы узнать, какие ключи она поддерживает.

Заметка основывается на источниках:

Рекомендуемые статьи:

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *