Процесс убит перед запуском в фоновом режиме

5

Я использую скрипт bash, script.shсодержащий команду cmd, запущенную в фоновом режиме:

#!/bin/bash

cmd &

Если я открываю эмулятор терминала и запускаю script.sh, cmdон корректно выполняется в фоновом режиме, как и ожидалось. То есть, пока script.shзакончился, cmdпродолжает работать в фоновом режиме, с PPID 1.

Но, если я открываю другой эмулятор терминала (скажу xfce4-терминал) от предыдущей (или в начале рабочего стола сессии, которая является моим реальным случаем использования), а также выполнять script.shпо

xfce4-terminal -H -x script.sh

cmdбольше не выполняется должным образом: он убит прекращением script.sh. Использование nohupдля предотвращения этого недостаточно. Я обязан поставить sleepкоманду после нее, иначе cmdон погибнет от прекращения действия script.sh, прежде чем от него отмежеваться.

Единственный способ , которым я нашел , чтобы cmdправильно выполнить в фоновом режиме, чтобы положить set -mв script.sh. Зачем это нужно в этом случае, а не в первом? Почему такая разница в поведении между двумя способами выполнения script.sh(и, следовательно, cmd)?

Я полагаю , что в первом случае, режим монитора не активируется, как можно видеть, поставив set -oв script.sh.

глиф
источник
1
Примечание: расширение файлов исполняемых файлов - плохая практика. (что происходит с вызовом сценариев, если вы переписываете на другом языке?)
ctrl-alt-delor
xterm -e nohup ./scriptработает для меня. Может быть проблема с xfce?
Стефан
@stefan Нет, вы обманываете;) Это также работает для меня с xfce4-terminalили gnome-terminal. Дело в том, что nohupэто должно быть вставлено в скрипт, мы не хотим, чтобы на весь скрипт влиял nohup, а просто cmd. Тем не менее, интересно, что это работает в этом случае, не меняя ничего внутри скрипта.
Символ

Ответы:

4

Процесс, cmdв котором предполагается запускаться, будет прерван SIGHUPсигналом между fork () и exec (), и любая nohupоболочка или другой материал не будет иметь возможности для запуска и будет иметь какой-либо эффект. (Вы можете проверить это с помощью strace)

Вместо того nohup, вы должны установить SIGHUPв SIG_IGN(игнорировать) в родительской оболочке перед выполнением вашей команды фона; если для обработчика сигнала установлено значение «игнорировать» или «по умолчанию», такое расположение будет наследоваться через fork () и exec (). Пример:

#! /bin/sh
trap '' HUP    # ignore SIGHUP
xclock &
trap - HUP     # back to default

Или же:

#! /bin/sh
(trap '' HUP; xclock &)

Если вы запустите этот скрипт с помощью xfce4-terminal -H -x script.sh, фоновая команда ( xclock &) не будет уничтожена SIGHUPотправленным при script.shзавершении.

Когда лидер сеанса (процесс, который «владеет» управляющим терминалом, script.shв вашем случае) завершается, ядро ​​отправит a SIGHUPвсем процессам из своей группы процессов переднего плана ; но set -mвключит управление заданиями, а начатые команды &будут помещены в группу фоновых процессов, и они не будут сигнализироваться SIGHUP.

Если управление заданиями не включено (по умолчанию для неинтерактивного сценария), команды, запущенные с, &будут запускаться в той же группе процессов переднего плана , а режим «фона» будет имитироваться путем перенаправления их ввода /dev/nullи разрешения их игнорировать SIGINT и SIGQUIT.

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

Дополнительные примечания:

«Режим удержания», кажется, отличается между xtermи xfce4-terminal(и, возможно, другими терминалами на основе vte). В то время как первый будет держать основную сторону pty открытой, последний разорвёт ее после запуска программы -eили -xвыхода из нее, что приведет к сбою любой записи на ведомую сторону EIO. xtermтакже будет игнорировать WM_DELETE_WINDOWсообщения (то есть не будет закрываться), пока все еще выполняются процессы из группы процессов переднего плана.

mosvy
источник
Я думаю, что вы на что-то. Но я не вижу , почему xtermбы посылая SIGHUPк script.shв первом примере из ОП. ОП не говорит, что терминал был закрыт
iruvar
Отлично, это шаг вперед! Теперь я лучше понимаю поведение второй команды. Но я не совсем понимаю, почему, в первом случае, нам не нужно ничего делать для cmdправильного выполнения в фоновом режиме. Связано ли это с интерактивной природой первой родительской оболочки? Есть ли какое-то неявное наследование от него в отношении SIGHUP?
Символ
в случае, когда ./script.shосновная программа на терминале не запущена, но запускается как задание переднего плана из интерактивной оболочки, ее группа процессов (также унаследованная cmd &запущенным из нее) перестает быть передовой группой процессов в терминале, как только как это вышло. SIGHUPотправляется только процессам из группы процессов переднего плана.
Мосвы
Вы можете проверить все это из другого окна с помощью ps t /dev/pts/6 o pid,pgid,tpgid,sid,args(замените /dev/pts/6фактическим pty). Если pgid = tpgid, то этот процесс получит a SIGHUP. Если pid = sid, то это процесс лидера / управления сеансом, а pid = sid = pgid = tpgid, то он «простаивает», то есть работает на переднем плане.
мосвы
1
@ ctrl-alt-delor - это не мой пример? Вы можете превратить его в функцию оболочки:bg_nohup(){ (trap '' HUP; "$@" &) }
Mosvy
0

Я играл с этим. Я не могу понять это, но вот что я обнаружил. Я использовал сон 3 в качестве моего cmd.

Эти две работы. Я понятия не имею, что lsделает в конце. Скобки и двойные nohup, ну, они делают подпроцесс (я думаю, это то, как nohupработает). Я понятия не имею, почему nohupсамостоятельно не работает.

#!/bin/bash

nohup nohup sleep 3 &
ls #no idea why I need this

а также

#!/bin/bash

(
nohup sleep 3 &
ls #no idea why I need this
)

/bin/trueработает вместо ls. Похоже, нам нужно вызвать внешнюю команду. До сих пор не знаю, почему.

Ctrl-Alt-Делор
источник
Я думаю , что ls, /bin/trueили другие внешние команды действуют как sleep nв том смысле , что она дает достаточно времени для cmdдля должным образом запущены в фоновом режиме. Действительно, в моем случае lsне каждый раз работает: это зависит от времени выполнения ( /bin/trueработает чаще, но не всегда). Кроме того, мне систематически не нужны двойные nohupили квадратные скобки, чтобы это работало, поэтому я думаю, что все это сводится к тому, чтобы дать некоторое время.
Символ
как насчетdisown -a
Боб Джонсон
@BobJohnson как вы предлагаете использовать disown -a? Я не вижу никакого преимущества в тестах.
Ctrl-Alt-Delor