Больше не нужно искать работу мечты — присоединяйтесь к команде Клауда

Команда Nohup в Linux

Миша Курушин
Миша Курушин
Технический писатель
02 октября 2024 г.
46
12 минут чтения
Средний рейтинг статьи: 5

nohup (сокращение от «no hangup») — это команда в операционных системах Linux, которая запускает процессы выполняемых команд таким образом, что они остаются активными после закрытия терминала консоли.

На уровне технической реализации nohup предотвращает распространение системного сигнала SIGHUP (Signal Hang UP), задача которого — сообщать запущенным процессам о потере соединения с управляющим терминалом пользователя.

Скажем так, когда вы подключаетесь к удаленному серверу по SSH, запускаете команду, которая выполняется некоторое время, и сразу же отключаетесь от терминала, то команда прекращает свое выполнение — процесс, который ее выполняет, будет остановлен.

Избежать этого можно с помощью nohup. Синтаксис команды довольно простой:

nohup [команда] [аргументы] &

Таким образом при использовании nohup указывается:

  • [команда] — название команды или путь до shell-скрипта.

  • [аргументы] (необязательно) — аргументы или флаги, которые передаются указанной для запуска команде.

  • & (необязательно) — знак амперсанда, указывающий nohup запустить процесс команды в фоновом режиме.

Дополнительно можно использовать (необязательно) знаки перенаправления вывода в произвольный файл.

В этом случае синтаксис команды становится следующим:

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 от демона

Может возникнуть закономерный вопрос: чем nohup отличается от классического демона в Linux? На первый взгляд может показаться, что это одно и то же.

Особенность демонов в том, что они постоянно работают в фоновом режиме. Очень продолжительное время. Неделями и месяцами. По сути, всегда. Например, это могут быть HTTP-серверы или базы данных. Устройство процессов-демонов всегда сложнее — это не одноразовые скрипты.

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

Например, это может быть процесс, сортирующий какие-то данные, или выполняющий последовательность удаленных запросов. Такие задачи однократны, но занимают время — было бы неудобно оставлять терминал открытым.

То есть с помощью nohup можно выполнять несколько долгих задач в фоновом режиме, занимаясь в это время другими делами.

Команда nohup — это не про запуск бесконечных демонов. Это про однократные, но долгие задачи.

Заключение

Команда nohup — встроенный в операционные системы Linux инструмент для выполнения процессов, не зависящих от состояния консольного терминала.

Таким образом nohup позволяет выполнять команды даже после отключения пользователя от системы, в том числе запускать процессы в фоновом режиме. В этом случае любой консольный вывод перенаправляется в произвольный файл — либо стандартный, либо явно указанный.

Однако важно помнить, что nohup не подходит для создания демонов — регулярно работающих процессов в фоновом режиме. Команда nohup — это про однократное или спорадическое выполнение продолжительных задач: удаленных запросов, выполнения сортировки, обработки файлов и так далее.

Хотите внести свой вклад?
Участвуйте в нашей контент-программе за
вознаграждение или запросите нужную вам инструкцию
img-server
02 октября 2024 г.
46
12 минут чтения
Средний рейтинг статьи: 5
Пока нет комментариев