nohup (сокращение от «no hangup») — это команда в операционных системах Linux, которая запускает процессы выполняемых команд таким образом, что они остаются активными после закрытия терминала консоли.
На уровне технической реализации nohup
предотвращает распространение системного сигнала SIGHUP
(Signal Hang UP), задача которого — сообщать запущенным процессам о потере соединения с управляющим терминалом пользователя.
Скажем так, когда вы подключаетесь к удаленному серверу по SSH, запускаете команду, которая выполняется некоторое время, и сразу же отключаетесь от терминала, то команда прекращает свое выполнение — процесс, который ее выполняет, будет остановлен.
Избежать этого можно с помощью nohup
. Синтаксис команды довольно простой:
nohup [команда] [аргументы] &
Таким образом при использовании nohup
указывается:
[команда]
— название команды или путь до shell-скрипта.
[аргументы]
(необязательно) — аргументы или флаги, которые передаются указанной для запуска команде.
&
(необязательно) — знак амперсанда, указывающий nohup
запустить процесс команды в фоновом режиме.
Дополнительно можно использовать (необязательно) знаки перенаправления вывода в произвольный файл.
В этом случае синтаксис команды становится следующим:
nohup [команда] [аргументы] & > [путь к файлу]
Перед работой с командой сперва необходимо проверить версию установленного nohup
:
nohup --version
Можно также использовать короткий способ записи:
nohup --v
Если nohup
присутствует в системе, в консоли появится примерно такой вывод:
nohup (GNU coreutils) 8.32
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Jim Meyering.
Как видно, в этом руководстве используется nohup
версии 8.32, которая работает на операционной системе Ubuntu 22.04.
Кстати, системную справку о команде можно получить так:
nohup --help
Дополнительно можно просмотреть полноценную документацию в формате Texinfo прямо в терминале консоли:
info nohup
Давайте запустим простой процесс, выводящий состояние текущего каталога, через nohup
:
nohup ls
В консоли появится информирующее (то есть не являющееся ошибкой) сообщение о том, что вывод указанной команды будет перенаправлен в файл nohup.out
:
nohup: ignoring input and appending output to 'nohup.out'
Давайте удостоверимся, что это действительно так:
ls
В консоли появится список существующих файлов и каталогов:
nohup.out resize.log snap
Теперь выведем содержимое нового файла:
cat nohup.out
В консоли появится следующий список:
nohup.out
resize.log
snap
Обратите внимание, что файл nohup.out
был создан перед выполнением команды ls
. В противном случае сохраненный консольный вывод был бы таким:
resize.log
snap
В созданный файл автоматически записываются выходные данные двух стандартных потоков:
stdout
— стандартный поток вывода.
stderr
— стандартный поток ошибок.
В этом примере команда ls
выполняется однократно — нет никакого смысла запускать ее через nohup
. Поэтому имеет смысл рассмотреть запуск процесса, выполнение которого будет достаточно продолжительным, чтобы успеть выйти из консольного терминала и вернуться обратно.
Например, мы могли бы сымитировать долгое выполнение команды с помощью собственного shell-скрипта, представляющего собой обычный таймер.
Давайте создадим его:
nano timer.sh
Внутри будет цикл, ведущий обратный отсчет каждую секунду:
#!/bin/sh
i=10
while [ "$i" -gt 0 ]; do
echo "$i"
sleep 1
i=$(( i - 1 ))
done
Также важно не забыть сделать созданный скрипт исполняемым файлом, чтобы не было ошибки при запуске:
chmod +x timer.sh
Теперь запустим скрипт, чтобы протестировать его работу:
./timer.sh
В терминале консоли каждую секунду начнут появляться числа от 10 до 1. Общий вывод будет таким:
10
9
8
7
6
5
4
3
2
1
Чтобы в дальнейшем не было путаницы, удалим ранее созданные файлы с выводами:
rm nohup.out
Теперь можно запустить созданный скрипт через nohup
:
nohup ./timer.sh
Как только начнется обратный отсчет, можно закрыть консольный терминал и вернуться в него уже через 10 секунд, выполнив переподключение к удаленному серверу через SSH.
Далее посмотрим содержимое файла с выводом:
cat nohup.out
Внутри будет все та же последовательность чисел:
10
9
8
7
6
5
4
3
2
1
Таким образом, запущенный процесс продолжал обратный отсчет даже после отключения пользователя от терминала консоли.
С помощью nohup
продолжительно выполняющийся процесс можно запустить в фоновом режиме. Это означает, что он будет активен и когда мы будем выполнять другие команды, и когда мы выйдем из консольного терминала, и когда мы в него вернемся.
Для примера можно запустить утилиту диагностики сети ping
, которая будет регулярно отправлять запрос на сайт Timeweb Cloud.
Давайте сперва протестируем отправку запроса без nohup
:
ping timeweb.cloud
В консоли появится следующий вывод:
PING timeweb.cloud (178.248.239.157) 56(84) bytes of data.
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=1 ttl=58 time=7.94 ms
При этом последняя строчка будет продолжать выводиться в терминал каждую секунду, информируя о результате очередного запроса:
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=2 ttl=58 time=7.62 ms
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=3 ttl=58 time=7.61 ms
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=4 ttl=58 time=7.64 ms
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=5 ttl=58 time=7.59 ms
Заранее очистим файл с консольными выводами:
rm nohup.out
Для запуска процесса в фоновом режиме через nohup
после аргументов команды нужно указать символ амперсанда:
nohup ping timeweb.cloud &
В консоли появится следующий вывод:
[1] 29649
root@3494829-yn55665:~# nohup: ignoring input and appending output to 'nohup.out'
Набор цифр в начале является идентификатором запущенного процесса.
Теперь можно выйти из консольного терминала и снова в него зайти.
Чтобы убедиться в том, что запущенный процесс до сих пор активен, нужно запросить список рабочих процессов:
pgrep -a ping
В консоли появится строка с идентификатором, именем и аргументом запущенного процесса:
29649 ping timeweb.cloud
Впоследствии с помощью этого идентификатора процесс можно будет остановить.
Кстати, для просмотра запущенных процессов можно воспользоваться другой командой:
ps aux | grep ping
Фактически тут используется конвейер из двух команд:
ps aux
— выводит список всех процессов.
grep ping
— находит в списке из вывода строку с ключевым словом «ping».
В консоли появится примерно такой вывод:
root 29649 0.0 0.1 7720 1264 pts/0 S 23:10 0:00 ping timeweb.cloud
root 29656 0.0 0.2 6480 2228 pts/0 S+ 23:10 0:00 grep --color=auto ping
В данном случае первая строчка — искомый процесс.
Кстати, можно смотреть за записью вывода в файл в режиме реального времени:
tail -f nohup.out
Команда tail
выводит последние строки указанного файла, а дополнительный флаг -f
позволяет делать вывод в режиме реального времени в момент дополнения файла другими процессами.
Поэтому в консоли появятся строки с результатами удаленных запросов, которые будут дополняться новым выводом запущенного процесса:
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=344 ttl=58 time=7.60 ms
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=345 ttl=58 time=7.56 ms
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=346 ttl=58 time=7.59 ms
...
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=354 ttl=58 time=7.62 ms
Фактически таким образом можно записывать консольный вывод в произвольный файл и одновременно показывать его в терминале.
Чтобы остановить запущенный процесс, нужно указать его идентификатор:
kill 29649
Теперь, если проверить список активных процессов, вывод будет пуст:
pgrep -a ping
Либо можно снова воспользоваться другим способом поиска процессов:
ps aux | grep ping
Тогда в выводе будет содержаться только процесс grep, который запускается для целей поиска:
root 30172 0.0 0.2 6480 2360 pts/0 S+ 23:13 0:00 grep --color=auto ping
Теперь, можно взглянуть на сохраненный в файле консольный вывод.
cat nohup.out
Вывод будет примерно таким:
PING timeweb.cloud (178.248.239.157) 56(84) bytes of data.
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=1 ttl=58 time=10.9 ms
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=2 ttl=58 time=7.65 ms
...
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=17 ttl=58 time=7.70 ms
Таким образом, запущенный процесс продолжает работать и записывать вывод в отдельный файл вне зависимости от активности консольного терминала.
Помимо прочего, через nohup
можно выполнять несколько команд в фоновом режиме.
Давайте сперва очистим ранее сохраненный вывод:
rm nohup.out
А потом запустим сразу 2 процесса в фоновом режиме:
nohup bash -c './timer.sh && ping timeweb.cloud' &
Обратите внимание, что в конце команды аналогично стоит знак амперсанда.
В этом примере у нас сперва отработает таймер (на это уйдет 10 секунд), после чего начнется регулярный цикл отправки удаленных запросов.
Поэтому, подождав около 15 секунд (в это время можно также попробовать закрыть и снова открыть терминал консоли), выведем файл с сохраненным консольным выводом:
cat nohup.out
Содержимое внутри будет примерно таким:
10
9
8
7
6
5
4
3
2
1
PING timeweb.cloud (178.248.239.157) 56(84) bytes of data.
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=1 ttl=58 time=7.90 ms
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=2 ttl=58 time=7.68 ms
...
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=7 ttl=58 time=7.67 ms
То есть внутри файла nohup.out
находится комбинируемый последовательный вывод — сначала отсчет таймера, потом череда удаленных запросов. Таким образом, указанные команды запускаются последовательно.
Поэтому точно так же можно запустить три и более команд:
nohup bash -c './timer.sh && ./timer.sh && ping timeweb.cloud' &
В этоv случае новый записанный вывод будет примерно таким:
10
9
8
7
6
5
4
3
2
1
10
9
8
7
6
5
4
3
2
1
PING timeweb.cloud (178.248.239.157) 56(84) bytes of data.
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=1 ttl=58 time=7.34 ms
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=2 ttl=58 time=7.56 ms
...
64 bytes from 178.248.239.157 (178.248.239.157): icmp_seq=7 ttl=58 time=7.24 ms
По умолчанию команда nohup
записывает вывод в файл nohup.out
. Тем не менее, при запуске процесса можно в явном виде указать файл для перенаправления вывода с помощью знака перенаправления:
nohup ./timer.sh > myout1
В консоли появится сообщение о перенаправлении потока ошибок и вывода:
nohup: ignoring input and redirecting stderr to stdout
Проверим состояние файловой системы:
ls
Как видно, появился ранее указанный файл:
myout1 nohup.out resize.log snap
Теперь посмотрим его содержимое:
cat myout1
Как видно, оно аналогично всем предыдущим выводам:
10
9
8
7
6
5
4
3
2
1
Схожим образом работает перенаправление вывода для процессов в фоновом режиме:
nohup ./timer.sh > myout1 &
Обратите внимание, что амперсанд указывается после перенаправления вывода.
Процесс таймера будет автоматически уничтожаться после завершения таймера — вручную ничего останавливать не надо.
А теперь давайте посмотрим на поведение команды nohup
при указании амперсанда перед перенаправлением.
Сперва удалим все существующие файлы с консольным выводом:
rm myout1 && rm nohup.out
И выполним такую команду:
nohup ./timer.sh & > myout1
В консоли появится стандартный вывод, сообщающий о создании фонового процесса.
Проверим состояние файловой системы:
ls
Как видно, у нас появились два новых файла — myout1
и nohup.out
:
myout1 nohup.out resize.log snap timer.sh
Тем не менее, запись будет выполняться только в nohup.out
, а файл myout1
создался исключительно потому, что было явно указано перенаправление.
Содержимое myout1
будет пустым:
cat myout1
А вот если проверить nohup.out
:
cat nohup.out
То внутри него окажется привычный вывод отсчета таймера:
10
9
8
7
6
5
4
3
2
1
Поэтому важно всегда указывать символ амперсанда (&
) в конце каждой командной строки, если требуется запускать процесс в фоновом режиме.
Также не забывайте контролировать активные процессы — не допускайте их дублирования, завершайте лишние и прорабатывайте механизмы автоматической остановки запущенных программ.
Это позволит избежать утечек вычислительных ресурсов и повысить безопасность разворачиваемых инфраструктур.
Может возникнуть закономерный вопрос: чем nohup
отличается от классического демона в Linux? На первый взгляд может показаться, что это одно и то же.
Особенность демонов в том, что они постоянно работают в фоновом режиме. Очень продолжительное время. Неделями и месяцами. По сути, всегда. Например, это могут быть HTTP-серверы или базы данных. Устройство процессов-демонов всегда сложнее — это не одноразовые скрипты.
Напротив, nohup
предназначен для одноразового использования. Обычно это некий сценарий, который выполняется продолжительно (минуты или часы), но все равно завершается.
Например, это может быть процесс, сортирующий какие-то данные, или выполняющий последовательность удаленных запросов. Такие задачи однократны, но занимают время — было бы неудобно оставлять терминал открытым.
То есть с помощью nohup
можно выполнять несколько долгих задач в фоновом режиме, занимаясь в это время другими делами.
Команда nohup
— это не про запуск бесконечных демонов. Это про однократные, но долгие задачи.
Команда nohup
— встроенный в операционные системы Linux инструмент для выполнения процессов, не зависящих от состояния консольного терминала.
Таким образом nohup
позволяет выполнять команды даже после отключения пользователя от системы, в том числе запускать процессы в фоновом режиме. В этом случае любой консольный вывод перенаправляется в произвольный файл — либо стандартный, либо явно указанный.
Однако важно помнить, что nohup
не подходит для создания демонов — регулярно работающих процессов в фоновом режиме. Команда nohup
— это про однократное или спорадическое выполнение продолжительных задач: удаленных запросов, выполнения сортировки, обработки файлов и так далее.