Я использую `&`: почему процесс не работает в фоновом режиме?

24

Я знаю, что могу добавить &команду для запуска процесса в фоновом режиме.

Я работаю по SSH в Ubuntu 12.04 и запускаю программу на Python с $python program.py &- но когда я иду, чтобы закрыть окно терминала, я получаю сообщение о том, что закрытие терминала убьет запущенный процесс.

Почему это? Я использую амперсанд для запуска процесса в фоновом режиме. Как я могу заставить его работать независимо от того, включен ли я в SSH?

bernie2436
источник
Дубликат unix.stackexchange.com/q/4004/69080
Джошуа Хубер
apt-get install screen, man screen
captcha

Ответы:

51

Когда вы закрываете окно терминала, эмулятор терминала отправляет сигнал SIGHUP процессу, который он выполняет, вашей оболочке. Ваша оболочка затем пересылает этот SIGHUP на все, что работает. В вашей локальной системе это ssh. Затем ssh пересылает сигнал SIGHUP на удаленную оболочку. Таким образом, ваша удаленная оболочка затем отправляет SIGHUP всем своим процессам, вашей фоновой программе.

Есть 2 способа обойти это.

  1. Отсоедините фоновую программу от вашей оболочки.
    1. Используйте disownкоманду после прохождения фонового процесса. Это заставит оболочку забыть об этом.
    2. Префикс вашей команды с nohup( nohup $python program.py &). Это выполняет то же самое, но с использованием промежуточного процесса. По сути, он игнорирует сигнал SIGHUP, а затем разветвляет и выполняет вашу программу, которая наследует настройки, а затем завершает работу. Поскольку она разветвлена, запускаемая программа не является дочерней для оболочки, и оболочка не знает об этом. И если он не устанавливает обработчик сигнала для SIGHUP, он все равно сохраняет действие игнорирования.
  2. Используйте logoutвместо закрытия окна терминала. Когда вы используете logout, это не SIGHUP, и поэтому оболочка не отправит SIGHUP никому из своих дочерних элементов.

Кроме того, вы должны убедиться, что ваша программа не выполняет запись в терминал через STDOUT или STDERR, так как оба из них больше не будут существовать после выхода из терминала. Если вы не перенаправите их на что-то подобное /dev/null, программа все равно будет работать, но если она попытается записать их, она получит SIGPIPE, а действие SIGPIPE по умолчанию - уничтожить процесс).

Патрик
источник
4
Технически, sshумирание вызывает разрыв соединения, а разрыв соединения - sshdна другом конце. Тот sshd, который управляет главной стороной псевдотерминала, на котором работает удаленная оболочка, когда он умирает, является зависанием (это похоже на отключение от реального терминала), поэтому система отправляет сигнал SIGHUP на удаленную оболочку.
Стефан Шазелас
@ StéphaneChazelas Это одна вещь, в которую я никогда не копался. Если это делает ядро, то как оно определяет, какой процесс SIGHUP? Очевидно, что он НЕ ДОПУСКАЕТ все с открытым дескриптором файла к этому TTY, поскольку программы будут работать до тех пор, пока они не попытаются его использовать. Так выбирает ли программа, которая в настоящее время читает из STDIN (поскольку только одна может читать из STDIN за один раз)?
Патрик
4
Неважно, ответил на мой вопрос. POSIX IEEE 1003.1, глава 11, если интерфейс терминала обнаруживает разрыв модема для управляющего терминала ... сигнал SIGHUP должен быть отправлен процессу управления .
Патрик
2
Также обратите внимание, что nohupгенерируется nohup.outфайл с выводом программы, с которой вы начинаете. Может быть раздражает удаление этого файла каждый раз, когда вы используете nohup для запуска приложения таким способом (или вам нужно перенаправить его вывод в /dev/null).
Руслан
1
Вместо того, чтобы nohup python program.py &я рекомендовал использовать setsid python program.pyвместо этого, который сразу же отказывается от программы.
Hitechcomputergeek
14

Процесс работает в фоновом режиме в терминале, но вывод из stdoutstderr) все еще отправляется в терминал. Чтобы остановить это, добавьте > /dev/null 2>&1перед &перенаправлением обоих выходов /dev/null- добавление disownтакже гарантирует, что процесс не будет завершен после закрытия терминала:

COMMAND > /dev/null 2>&1 & disown

В вашем случае это будет:

python program.py > /dev/null 2>&1 & disown
Уилф
источник
3

Эти &команды оператора Разделяет работать параллельно, так же , как ;Разделяет команды для запуска последовательно. Оба вида команд будут по-прежнему выполняться как дочерние элементы процесса оболочки .

Таким образом, когда вы закроете оболочку, которая запустила этих детей, дети тоже закроются.

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

большой нос
источник
1

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

nohup python program.py &
Barmar
источник
1

После окончания команды ampersand ( &) в командной строке выполните команду bg:

bash> python program.py &  
bash> bg  

Это поместит команду "&" в фоновый режим.

bash> jobs  

Это перечислит задания, работающие в фоновом режиме

bash> fg 1   

Это выведет задание № 1 на первый план

Другой способ (чтобы выйти из системы)

bash> at now  
bash> /full/path/python /full/path/program.py  
bash> ^d   `(# That is, Control-D, to run the command, Control-C to cancel)`  

Команде можно отправить несколько строк at, прежде чем
см man at. ^ D (Control-D) .

Мартин
источник