Задачи и фоновый запуск
Управление задачами позволяет приостанавливать, переводить в фон и на передний план процессы внутри сессии оболочки. nohup и disown защищают долго выполняющиеся задачи от SIGHUP при закрытии терминала — без них одного фонового запуска недостаточно.
Ты запускаешь долгую сборку, понимаешь, что нужно сделать что-то ещё в том же терминале, и инстинктивно нажимаешь Ctrl-C — убивая сборку полностью. Или запускаешь задачу в фоне с &, закрываешь терминал, и обнаруживаешь задачу мёртвой. Оба случая можно избежать. В оболочке есть полноценная подсистема управления задачами: приостановить, возобновить, перевести в фон, на передний план и отвязать. Зная эти пять операций, ты перестанешь тратить ни время, ни вычислительные ресурсы.
После этого урока ты сможешь запускать команду в фоне с &, приостанавливать выполняющуюся команду с Ctrl-Z, проверять задачи с jobs, перемещать задачи между передним планом и фоном с fg и bg, и защищать долго выполняющиеся задачи от закрытия терминала с nohup и disown.
& сразу запускает команду в фоновом режиме. Добавь & к любой команде — оболочка переводит дочерний процесс в фоновую группу процессов, печатает номер задачи и PID, и сразу возвращает приглашение.
python train.py &
# [1] 2047[1] — номер задачи, локальный индекс оболочки. 2047 — PID. Процесс выполняется; приглашение доступно. Его stdout и stderr всё ещё идут на терминал, если не перенаправить.
python train.py > train.log 2>&1 &Теперь вывод идёт в train.log и терминал чистый. Фоновый процесс всё ещё в той же сессии, что и оболочка — он получит SIGHUP при завершении сессии (шаг 5).
Ctrl-Z отправляет SIGTSTP группе процессов переднего плана, приостанавливая её. Процесс не убивается — он ставится на паузу (STAT T). Оболочка восстанавливает управление и выводит:
^Z
[1]+ Stopped vim notes.txtЗадача теперь остановлена. Её состояние в /proc/<PID>/status — T (остановлен). Она удерживает всю память, открытые файлы и сокеты — ничего не освобождается. Позже можно возобновить.
Почему это важно: Ctrl-Z — способ выйти из интерактивной программы без потери работы. Приостанови vim, выполни команды в оболочке, затем верни vim обратно.
jobs выводит все задачи текущей сессии оболочки.
jobs
# [1]- Stopped vim notes.txt
# [2]+ Running python train.py &+ отмечает текущую задачу (последнюю выведенную на передний план или остановленную). - — предыдущую. Задачи адресуются по номеру: %1, %2, или %% для текущей.
fg выводит задачу на передний план. Подключает stdin/stdout к терминалу и помещает процесс обратно в группу процессов переднего плана.
fg %1 # вывести задачу 1 (vim) на передний план
fg # вывести текущую задачу (отмеченную +) на передний планbg возобновляет остановленную задачу в фоне. Отправляет SIGCONT, но не перемещает на передний план.
bg %1 # возобновить задачу 1 в фонеnohup делает команду иммунной к SIGHUP. При выходе из системы или закрытии терминала оболочка отправляет SIGHUP всей своей группе процессов. Любая фоновая задача без защиты погибнет. nohup перенаправляет stdin из /dev/null, по умолчанию добавляет stdout+stderr в nohup.out, и устанавливает обработчик игнорирования SIGHUP перед exec командды.
nohup python train.py > train.log 2>&1 &
echo $! # PID только что запущенной фоновой задачиПроцесс теперь переживёт закрытие терминала. nohup.out используется только если ты сам не перенаправляешь — всегда перенаправляй явно, чтобы не засорять каталог.
disown убирает задачу из таблицы задач оболочки постфактум. Если забыл использовать nohup, но задача уже запущена — disown разрывает связь оболочка-задача. Оболочка больше не будет отправлять SIGHUP этому процессу при выходе.
./long-script.sh & # забыли nohup
jobs # [1]+ Running ./long-script.sh
disown %1 # убрать из таблицы задач
jobs # (пусто — оболочка больше не отслеживает)Процесс теперь осиротел с точки зрения оболочки. Linux перепривязывает его к PID 1 (init), который никогда не отправляет SIGHUP. Процесс выполняется до завершения или явного уничтожения.
disown -h оставляет задачу в таблице, но помечает её как не получающую SIGHUP — полезно, если всё ещё хочешь видеть её в jobs.
Запустить долгий бэкап, проверить на полпути, затем защитить от выхода из системы.
# Запустить бэкап в фоне с захватом вывода
tar czf /backup/home.tar.gz /home/alice > /tmp/backup.log 2>&1 &
echo "PID: $!"
# Проверить прогресс без прерывания
jobs
tail -f /tmp/backup.log # Ctrl-C выйти из tail, бэкап продолжается
# Понимаешь, что нужно закрыть SSH-сессию.
# Защитить задачу:
disown %%
# Убедиться, что задача отвязана
jobs # пусто
ps aux | grep tar # всё ещё выполняетсяЕсли бы использовал nohup при запуске:
nohup tar czf /backup/home.tar.gz /home/alice > /tmp/backup.log 2>&1 &Оба подхода работают; nohup при запуске проще. disown спасает, когда забыл.
▸Почему это работает
Управление задачами (&, fg, bg, jobs) — функция интерактивных оболочек. В неинтерактивных скриптах (запущенных через cron, systemd или CI-пайплайны) управление задачами отключено по умолчанию. Фоновый & всё ещё работает для форка процесса, но fg и bg завершатся с ошибкой «no job control». Для долго выполняющихся процессов в таких контекстах используй менеджеры процессов (systemd-юниты, supervisor), а не управление задачами оболочки.
▸Частая ошибка
Запуск задачи в фоне с & НЕ защищает её от SIGHUP. Это самая распространённая ошибка управления задачами. sleep 3600 & и затем закрытие терминала убивает sleep. Флаг фонового режима означает только «не блокировать приглашение» — он ничего не говорит об иммунитете к SIGHUP. Всегда сочетай & либо с nohup (при запуске), либо с disown (постфактум), когда нужно, чтобы задача пережила закрытие терминала.
Ты запускаешь: python train.py & затем закрываешь терминал. Процесс обучения погибает. Что нужно было сделать?
& запускает команду в фоне; Ctrl-Z приостанавливает процесс переднего плана (SIGTSTP, STAT T). jobs перечисляет задачи по номерам; fg %n выводит задачу на передний план; bg %n возобновляет остановленную задачу в фоне (SIGCONT). Фоновые задачи всё равно получают SIGHUP при закрытии терминала — одного & недостаточно для защиты. nohup игнорирует SIGHUP при запуске и перенаправляет вывод в nohup.out; disown убирает уже запущенную задачу из таблицы задач оболочки, разрывая связь SIGHUP.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.