Я использую скрипт 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
.
xterm -e nohup ./script
работает для меня. Может быть проблема с xfce?xfce4-terminal
илиgnome-terminal
. Дело в том, чтоnohup
это должно быть вставлено в скрипт, мы не хотим, чтобы на весь скрипт влиялnohup
, а простоcmd
. Тем не менее, интересно, что это работает в этом случае, не меняя ничего внутри скрипта.Ответы:
Процесс,
cmd
в котором предполагается запускаться, будет прерванSIGHUP
сигналом между fork () и exec (), и любаяnohup
оболочка или другой материал не будет иметь возможности для запуска и будет иметь какой-либо эффект. (Вы можете проверить это с помощьюstrace
)Вместо того
nohup
, вы должны установитьSIGHUP
вSIG_IGN
(игнорировать) в родительской оболочке перед выполнением вашей команды фона; если для обработчика сигнала установлено значение «игнорировать» или «по умолчанию», такое расположение будет наследоваться через fork () и exec (). Пример:Или же:
Если вы запустите этот скрипт с помощью
xfce4-terminal -H -x script.sh
, фоновая команда (xclock &
) не будет уничтоженаSIGHUP
отправленным приscript.sh
завершении.Когда лидер сеанса (процесс, который «владеет» управляющим терминалом,
script.sh
в вашем случае) завершается, ядро отправит aSIGHUP
всем процессам из своей группы процессов переднего плана ; ноset -m
включит управление заданиями, а начатые команды&
будут помещены в группу фоновых процессов, и они не будут сигнализироватьсяSIGHUP
.Если управление заданиями не включено (по умолчанию для неинтерактивного сценария), команды, запущенные с,
&
будут запускаться в той же группе процессов переднего плана , а режим «фона» будет имитироваться путем перенаправления их ввода/dev/null
и разрешения их игнорироватьSIGINT
иSIGQUIT
.Процессы запускаются таким образом из сценария, который когда-то выполнялся как задание переднего плана, но который уже завершился, также не будет сигнализироваться
SIGHUP
, поскольку их группа процессов (унаследованная от мертвого родителя) больше не является приоритетной группой в терминале.Дополнительные примечания:
«Режим удержания», кажется, отличается между
xterm
иxfce4-terminal
(и, возможно, другими терминалами на основе vte). В то время как первый будет держать основную сторону pty открытой, последний разорвёт ее после запуска программы-e
или-x
выхода из нее, что приведет к сбою любой записи на ведомую сторонуEIO
.xterm
также будет игнорироватьWM_DELETE_WINDOW
сообщения (то есть не будет закрываться), пока все еще выполняются процессы из группы процессов переднего плана.источник
xterm
бы посылаяSIGHUP
кscript.sh
в первом примере из ОП. ОП не говорит, что терминал был закрытcmd
правильного выполнения в фоновом режиме. Связано ли это с интерактивной природой первой родительской оболочки? Есть ли какое-то неявное наследование от него в отношении SIGHUP?./script.sh
основная программа на терминале не запущена, но запускается как задание переднего плана из интерактивной оболочки, ее группа процессов (также унаследованнаяcmd &
запущенным из нее) перестает быть передовой группой процессов в терминале, как только как это вышло.SIGHUP
отправляется только процессам из группы процессов переднего плана.ps t /dev/pts/6 o pid,pgid,tpgid,sid,args
(замените/dev/pts/6
фактическим pty). Если pgid = tpgid, то этот процесс получит aSIGHUP
. Если pid = sid, то это процесс лидера / управления сеансом, а pid = sid = pgid = tpgid, то он «простаивает», то есть работает на переднем плане.bg_nohup(){ (trap '' HUP; "$@" &) }
Я играл с этим. Я не могу понять это, но вот что я обнаружил. Я использовал сон 3 в качестве моего cmd.
Эти две работы. Я понятия не имею, что
ls
делает в конце. Скобки и двойныеnohup
, ну, они делают подпроцесс (я думаю, это то, какnohup
работает). Я понятия не имею, почемуnohup
самостоятельно не работает.а также
/bin/true
работает вместоls
. Похоже, нам нужно вызвать внешнюю команду. До сих пор не знаю, почему.источник
ls
,/bin/true
или другие внешние команды действуют какsleep n
в том смысле , что она дает достаточно времени дляcmd
для должным образом запущены в фоновом режиме. Действительно, в моем случаеls
не каждый раз работает: это зависит от времени выполнения (/bin/true
работает чаще, но не всегда). Кроме того, мне систематически не нужны двойныеnohup
или квадратные скобки, чтобы это работало, поэтому я думаю, что все это сводится к тому, чтобы дать некоторое время.disown -a
disown -a
? Я не вижу никакого преимущества в тестах.