Фоновые задачи: jobs, fg, bg и nohup

Job control — функция интерактивного shell, которая объединяет процессы pipeline в задания и позволяет переключать их между foreground, background и stopped состояниями. Это удобно для временной работы в терминале, но не заменяет диспетчер сервисов.

Запуск в фоне и PID

Амперсанд возвращает управление shell, а $! содержит PID последнего фонового pipeline или процесса в предусмотренной Bash форме.

sleep 120 &
pid=$!
printf 'started pid=%s\n' "$pid"
jobs -l
wait "$pid"

jobs знает только задания текущего shell. В новом терминале список пуст, хотя процесс может продолжать жить. Для общего наблюдения нужны ps, service manager или приложение, которое хранит собственную identity.

Foreground, stop и continue

Foreground job владеет терминалом и получает ввод. Ctrl+Z обычно отправляет SIGTSTP и останавливает группу. bg %1 продолжает её в фоне, fg %1 возвращает на передний план. Номер job %1 не является PID.

sleep 300
# В интерактивном терминале: Ctrl+Z
jobs
bg %1
fg %1

Команды job control могут быть выключены в неинтерактивном shell. Автоматизация не должна зависеть от ручных номеров заданий.

Что решает nohup

nohup настраивает игнорирование SIGHUP для запускаемой команды и при необходимости перенаправляет вывод. Это помогает короткой задаче пережить закрытие терминала, но не предоставляет restart policy, readiness, ограничение ресурсов, ротацию логов или управляемые секреты.

nohup sh -c 'sleep 5; date -Is' >/tmp/nohup-demo.log 2>&1 &
pid=$!
printf '%s\n' "$pid"

Для постоянного процесса используйте systemd service. Для задач сессии можно рассмотреть terminal multiplexer, но его состояние тоже нужно осознанно наблюдать.

Ошибка и диагностика

Частая ошибка — запустить сервер через command &, закрыть SSH и считать его сервисом. Процесс может получить SIGHUP, потерять stdin, писать в закрытый terminal или остаться без владельца. Проверьте PPID, дескрипторы в /proc/PID/fd, журнал и способ рестарта. Если работа постоянная, перенесите её в unit вместо добавления всё большего числа shell-трюков.

Практика

Запустите два sleep в фоне, найдите их через jobs -l, дождитесь одного по PID и завершите второй через TERM. Затем выполните короткую nohup-команду с явным stdout/stderr и после её завершения проверьте файл и status, если процесс остаётся дочерним текущего shell.

Что важно запомнить

Источники