Вопрос или проблема
Каковы различия между
$ nohup foo
и
$ foo &
и
$ foo &
$ disown
Давайте сначала посмотрим, что происходит, если программа запускается из интерактивной оболочки (соединенной с терминалом) без & (и без каких-либо перенаправлений). Предположим, вы только что набрали foo:
Создается процесс, выполняющий foo.
Процесс унаследует stdin, stdout и stderr от оболочки. Следовательно, он также подключен к тому же терминалу.
Если оболочка получает SIGHUP, она также отправляет SIGHUP процессу (что обычно приводит к завершению процесса).
В противном случае оболочка ждет (блокируется) до тех пор, пока процесс не завершится или не будет остановлен.
Теперь давайте посмотрим, что происходит, если вы помещаете процесс в фоновый режим, то есть набираете foo &:
Создается процесс, выполняющий foo.
Процесс унаследует stdout/stderr от оболочки (так что он все еще записывает на терминал).
Процесс в принципе также унаследует stdin, но как только он пытается прочитать из stdin, он останавливается.
Он помещается в список фоновых задач, которым управляет оболочка, что означает, в частности:
Он отображается с помощью jobs и к нему можно получить доступ с помощью %n (где n — номер задачи).
Его можно превратить в задачу переднего плана с помощью fg, в этом случае он продолжает выполняться так, как если бы вы не использовали & (и если он был остановлен из-за попытки прочитать из стандартного ввода, теперь он может продолжить чтение с терминала).
Если оболочка получает SIGHUP, она также отправляет SIGHUP процессу. В зависимости от оболочки и, возможно, от настроек для оболочки, при завершении оболочки она также отправит SIGHUP процессу.
Теперь disown удаляет задачу из списка задач оболочки, так что все вышеупомянутые подпункты больше не применимы (включая отправку SIGHUP процессу оболочкой). Однако имейте в виду, что он все еще подключен к терминалу, поэтому если терминал будет уничтожен (что может произойти, если это был pty, как те, что создаются xterm или ssh, и управляющая программа завершена, путем закрытия xterm или завершения SSH-соединения), программа завершится, как только попытается прочитать из стандартного ввода или записать в стандартный вывод.
Что делает nohup, так это эффективно отделяет процесс от терминала:
Он закрывает стандартный ввод (программа не сможет читать какие-либо входные данные, даже если она запущена в переднем плане; она не будет остановлена, но получит код ошибки или EOF).
Он перенаправляет стандартный вывод и стандартную ошибку в файл nohup.out, так что программа не завершится из-за записи в стандартный вывод, если терминал выйдет из строя, так что все, что записывает процесс, не теряется.
Он предотвращает получение процессом SIGHUP (таково его название).
Обратите внимание, что nohup не удаляет процесс из управления задачами оболочки и также не помещает его в фоновый режим (но поскольку задача nohup в переднем плане более или менее бесполезна, ее обычно помещают в фоновый режим с помощью &). Например, в отличие от disown, оболочка по-прежнему сообщит вам, когда задача nohup завершилась (если только оболочка не завершится раньше, конечно).
Итак, подводя итог:
& помещает задачу в фоновый режим, то есть блокирует ввод от оболочки и делает так, что оболочка не ждет завершения.
disown удаляет процесс из управления задачами оболочки, но он все еще остается подключенным к терминалу. Одним из результатов является то, что оболочка не отправит ему SIGHUP. Очевидно, это можно применять только к фоновых задачам, поскольку вы не можете ввести это, когда задача переднего плана выполняется.
nohup отключает процесс от терминала, перенаправляет его вывод в nohup.out и защищает его от SIGHUP. Один из эффектов (по названию) состоит в том, что процесс не получит никаких отправленных SIGHUP. Он совершенно независим от управления задачами и в принципе может быть использован также для фоновых задач (хотя это не очень полезно).
Использование & приводит к запуску программы в фоновом режиме, так что вы получите новый提示 оболочки вместо блокировки до завершения программы. nohup и disown в значительной степени не связаны; они подавляют сигналы SIGHUP (hangup), чтобы программа не была автоматически завершена, когда управляющий терминал закрывается. nohup делает это, когда задача впервые начинается. Если вы не используете nohup для задачи, когда она начинается, вы можете использовать disown, чтобы модифицировать запущенную задачу; без аргументов он модифицирует текущую задачу, которая только что была помещена в фоновый режим.
Вот мой опыт попытки запустить soffice в фоновом режиме после не заканчивающейся команды (например, tail). Для этого примера я буду использовать sleep 100.
Во всех случаях ниже я выполняю так:
./scriptfile
&
#!/bin/bash
/opt/libreoffice4.4/program/soffice -invisible -nofirststartwizard &
sleep 100
Я вижу логи soffice / при нажатии Ctrl-C soffice останавливается
nohup .. &
#!/bin/bash
nohup /opt/libreoffice4.4/program/soffice -invisible -nofirststartwizard &
sleep 100
Я не вижу логов soffice / при нажатии Ctrl-C soffice останавливается
& disown
#!/bin/bash
/opt/libreoffice4.4/program/soffice -invisible -nofirststartwizard & disown
sleep 100
Я вижу логи soffice / при нажатии Ctrl-C soffice останавливается
setsid .. &
#!/bin/bash
setsid /opt/libreoffice4.4/program/soffice -invisible -nofirststartwizard &
sleep 100
Я вижу логи soffice / при нажатии Ctrl-C soffice НЕ ОСТАНАВЛИВАЕТСЯ
Чтобы сэкономить место:
nohup setsid .. : не показывает логи / soffice НЕ ОСТАНАВЛИВАЕТСЯ при Ctrl-C
nohup с & disown в конце : не показывает логи / soffice останавливается при Ctrl-C
Краткий ответ:
используйте & когда хотите, чтобы ваша команда выполнялась в фоновом режиме, чтобы вы могли запустить следующую, не дожидаясь ее завершения
используйте nohup, если хотите, чтобы ваша команда игнорировала сигнал SIGHUP, чтобы, когда вы закроете терминал или выйдете из сеанса ssh, процесс продолжал работу
используйте disown, если вы забыли запустить команду с nohup и хотите выйти, не завершая процесс (он disown все процессы в фоновом режиме). Чтобы поместить процесс в фоновый режим и disown его:
Ctrl+Z, чтобы приостановить процесс
bg, чтобы поместить остановленный процесс в фоновый режим
disown, чтобы сделать процесс независимым от завершения терминала
Смотрите также утилиту daemonize(1), которая обрабатывает все задачи по запуску “истинного фонового” процесса. Согласно ее документации:
daemonize запускает команду как Unix-демон. Как определено в книге У. Ричарда Стивенса 1990 года “Unix Network Programming” (Addison-Wesley, 1990), демон — это “процесс, который выполняется в фоновом режиме (т.е. без связанного терминала или сеанса входа) и ждет, чтобы произошло событие или ждет выполнения определенной задачи на периодической основе”. При старте типичная программа демона будет:
Закрывать все открытые файловые дескрипторы (особенно стандартный ввод, стандартный вывод и стандартную ошибку)
Изменять свой рабочий каталог на корневую файловую систему, чтобы гарантировать, что он не заблокирует другую файловую систему и не предотвратит ее размонтирование
Сбросить значение umask
Запускаться в фоновом режиме (т.е. fork)
Отключаться от своей группы процессов (обычно оболочка), чтобы изолировать себя от сигналов (таких как HUP), отправляемых в группу процессов
Игнорировать все сигналы ввода/вывода терминала
Отключаться от управляющего терминала (и принимать меры для того, чтобы не получить его обратно)
Обрабатывать любые сигналы SIGCLD
Большинство программ, которые предназначены для запуска в качестве демонов, выполняют эту работу самостоятельно. Однако вы время от времени наткнетесь на программу, которая этого не делает. Когда вам нужно запустить демон, который правильно не делает себя настоящим Unix-демоном, вы можете использовать daemonize, чтобы заставить его работать как настоящий демон.
Это заменяет всю путаницу с &/nohup/disown.
& помещает задачу в фоновый режим, т.е. блокирует ввод от оболочки и делает так, что оболочка не ждет завершения.
nohup и disown в обоих случаях можно сказать, что подавляют stdin от терминала и SIGHUP, но по-разному. nohup работает, когда задача инициализируется, disown работает после факта.
nohup также перенаправляет stderr в stdout и stdout в $HOME/nohup.out. Он не блокирует отправку других сигналов, посылаемых косвенно из исходной оболочки.
disown не перенаправляет stdout или stderr. Он просто удаляет процесс из таблицы задач оболочки, так что никакие сигналы не будут косвенно отправлены процессу из исходной оболочки.
Это не так сложно.
man nohup (объяснение: команда nohup)
NOHUP(1)
Команды пользователя
NOHUP(1)
ИМЯ
nohup – запуск команды, не подверженной отключениям, с выводом на неназначенный терминал
man bash (объяснение: оператор &)
Списки:
операторов ;, &, &&, или ||, и, возможно, заканчиваются одним из ;
, & или . Из этих операторов списка, && и || имеют равный приоритет, за которыми следуют ; и &, которые также имеют равный приоритет. Последовательность из одного или более переводов строки может появиться в списке вместо точки с запятой, чтобы разделить команды. Если команда заканчивается управляющим оператором &, оболочка выполняет команду в фоновом режиме в подсистеме. Оболочка не ждет завершения команды, и возвращаемый статус равен 0. Это называется асинхронными командами. Команды, разделенные ; выполняются последовательно; оболочка ждет, пока каждая команда завершится по очереди. Возвращаемый статус — это статус выхода последней выполненной команды. AND и OR списки — это последовательности одной или нескольких конвейеров, разделенные управляющими операторами && и || соответственно. AND и OR списки выполняются с левосторонней ассоциативностью. Список AND имеет форму ‘команда1 && команда2’; команда2 выполняется, если и только если команда1 возвращает статус выхода равным нулю (успех). Список — это последовательность одной или нескольких конвейеров, разделенных одним
man disown с linuxcommand.org (Web)[1]
ИМЯ
disown – Удалить задачи из текущей оболочки.
СИНТАКСИС
disown [-h] [-ar] [jobspec … | pid …]
ОПИСАНИЕ
Удаляет задачи из текущей оболочки.
Удаляет каждый аргумент JOBSPEC из таблицы активных задач. Без каких-либо JOBSPEC оболочка использует свое представление о текущей задаче.
И это все…
RTFM, как это всегда будет.
Ответ или решение
Различия между nohup, disown и & в Unix-подобных операционных системах
Когда речь идет о запуске процессов в Unix-подобных операционных системах, три важных инструмента, которые помогают управлять поведением процессов, это nohup
, disown
и &
. Каждое из этих средств имеет свои особенности и предназначение. Давайте подробно рассмотрим каждое из них.
1. &
– Запуск в фоновом режиме
Когда вы добавляете &
в конце команды, например:
foo &
Это означает, что процесс foo
запускается в фоновом режиме. Некоторые ключевые моменты о данном механизме:
- Блокировка ввода: Процесс, запущенный с
&
, унаследует стандартный ввод (stdin), стандартный вывод (stdout) и стандартный поток ошибок (stderr) из оболочки. Если он попытается читать ввод, то будет остановлен. - Не блокирует оболочку: Оболочка не будет ждать завершения процесса и вернет контроль пользователю сразу же.
- Обработка сигналов: Если оболочка получит сигнал
SIGHUP
(обычно это происходит при закрытии терминала), она отправитSIGHUP
всем процессам, запущенным в фоновом режиме.
2. nohup
– Защита от сигналов SIGHUP
Команда nohup
используется, чтобы запускать процессы, которые не должны завершаться при получении сигнала SIGHUP
. Например:
nohup foo &
При использовании nohup
происходят следующие действия:
- Изоляция от терминала:
nohup
закрывает стандартный ввод (stdin) для команды. Это значит, что команда не сможет читать ввод, даже если она работает в переднем или фоновом режиме. - Переадресация вывода: Стандартные вывод и стандартный поток ошибок перенаправляются в файл
nohup.out
, что позволяет избежать потери информации, если терминал исчезнет. - Неслышимость к SIGHUP: Процесс, запущенный с помощью
nohup
, не получает сигналSIGHUP
, что позволяет ему продолжать выполнение даже при разрыве соединения с терминалом.
Однако стоит учитывать, что nohup
не удаляет процесс из таблицы задач оболочки, и он по-прежнему может быть отслежен и управляем (например, завершение через kill
).
3. disown
– Удаление задач из таблицы оболочки
Команда disown
применяется для удаления фонового задания из таблицы задач текущей оболочки. Это делается следующим образом:
foo & disown
При этом происходит следующее:
- Удаление из таблицы задач: Процесс больше не отслеживается оболочкой, что значит, что при выполнении оболочки
SIGHUP
больше не будет отправлен этому процессу. - Не защищает от закрытия терминала: Хотя процесс больше не принадлежит оболочке и не получит SIGHUP, он все еще остается связанным с терминалом. Это означает, что если терминал будет закрыт, процесс может завершиться, если он попытается читать ввод или записывать вывод.
Практические примеры и их последствия
Зависимо от стратегии запуска, поведение процесса будет различаться. Рассмотрим примеры, когда используется soffice
(LibreOffice) в фоновом режиме с sleep
:
-
Просто
&
:
При использовании&
, программаsoffice
будет запущена в фоновом режиме, однако будет завершена при вводеCtrl+C
, так как где-то в пути она будет ожидать ввод. -
Использование
nohup
:
С использованиемnohup
,soffice
игнорируетSIGHUP
и перенаправляет вывод, тем не менее, еслиnohub
не добавлен заранее, процессы все равно будут отключены при закрытии. -
Комбинация
& disown
:
Здесь добавлениеdisown
к команду, после указания&
, уберет из таблицы задач. Несмотря на это, процесс может быть завершен, если терминал был закрыт. -
Использование
setsid
:
Для создания настоящего фонового процесса можно использоватьsetsid
, который полностью отсоединит процесс от терминала. В этом случае выполнение контролировать черезnohup
.
Заключение
Каждый из этих инструментов (nohup
, disown
, &
) полезен в своем собственном контексте. &
позволяет запускать команды в фоновом режиме, nohup
защищает команды от сигналов, а disown
удаляет их из управления оболочкой. Понимание этих различий жизненно важно для эффективного управления процессами в Unix-подобных системах, особенно в ситуациях, когда необходимо обеспечить длительную работу приложений без контроля со стороны пользователя.