Фоновые задачи: 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.
Что важно запомнить
- Job — понятие конкретного shell; PID — identity процесса в namespace.
waitпозволяет получить status известного фонового дочернего процесса.- nohup меняет обработку hangup, но не делает команду надёжным сервисом.