linux команда setsid
Я пытаюсь написать оболочку, которая будет выполнять сценарий в качестве лидера сеанса.
Меня смущает поведение команды linux setsid
. Рассмотрим этот скрипт, называемый test.sh
:
#!/bin/bash
SID=$(ps -p $$ --no-headers -o sid)
if [ $# -ge 1 -a $$ -ne $SID ] ; then
setsid bash test.sh
echo pid=$$ ppid=$PPID sid=$SID parent
else
sleep 2
echo pid=$$ ppid=$PPID sid=$SID child
sleep 2
fi
выход отличается в зависимости от того, выполняется ли он или получен:
$ bash
$ SID=$(ps -p $$ --no-headers -o sid)
$ echo pid=$$ ppid=$PPID sid=$SID
pid=9213 ppid=9104 sid= 9104
$ ./test.sh 1 ; sleep 5
pid=9326 ppid=9324 sid= 9326 child
pid=9324 ppid=9213 sid= 9104 parent
$ . ./test.sh 1 ; sleep 5
pid=9213 ppid=9104 sid= 9104 parent
pid=9336 ppid=1 sid= 9336 child
$ echo $BASH_VERSION
4.2.8(1)-release
$ exit
exit
Итак, мне кажется, что setsid
возвращает немедленно, когда скрипт получен, но он ждет своего ребенка, когда скрипт будет выполнен.
Почему наличие управляющего tty иметь какое-либо отношение к setsid
? Спасибо!
Edit: для уточнения я добавил PID/ppid/Sid отчетность ко всем соответствующим командам.
3 ответов
исходный код setsid
утилиты на самом деле очень проста. Вы заметите, что это только fork()
s, Если он видит, что его идентификатор процесса и идентификатор группы процессов равны (т. е. если он видит, что это лидер группы процессов) - и что он никогда wait()
s для дочернего процесса: если это fork()
s, затем родительский процесс сразу возвращается. Если это не fork()
, то это дает вид wait()
ing для ребенка, но на самом деле то, что происходит просто это is ребенок, и это Баш, который wait()
ing (как всегда). (Конечно, когда это действительно fork()
, Баш не может wait()
для ребенка он создает, потому что обрабатывает wait()
для их детей, а не для их внуков.)
поэтому поведение, которое вы видите, является прямым следствием другого поведения:
- при выполнении
. ./test.sh
илиsource ./test.sh
или что-то еще - или, если на то пошло, когда вы просто запускаетеsetsid
непосредственно из подсказки Bash-Bash запуститсяsetsid
с новым процессом-group-ID для Контрольная работа целей, такsetsid
будет иметь тот же идентификатор процесса, что и его идентификатор группы процессов (то есть это лидер группы процессов), поэтому он будетfork()
и неwait()
. - при выполнении
./test.sh
илиbash test.sh
или что-то еще, и он запускаетsetsid
,setsid
будет частью той же группы процессов, что и скрипт, который ее запускает, поэтому его process-ID и process-group-ID будут другой, так что не будетfork()
, поэтому это даст видимость ожидания (без фактическогоwait()
ing).
set -x чтобы убедиться, что вы видите вещи правильно?
$ ./test.sh 1 child parent $ . test.sh 1 child $ uname -r 3.1.10 $ echo $BASH_VERSION 4.2.20(1)-release
при работе ./test.sh 1
, родитель скрипта-интерактивная оболочка-является лидером сеанса, поэтому $$ != $SID
и условие истинно.
при работе . test.sh 1
, интерактивная оболочка выполняет сценарий в процессе и является собственным лидером сеанса, поэтому $$ == $SID
и условное значение равно false, поэтому никогда не выполняется внутренний дочерний сценарий.
Я не вижу никаких проблем с вашим сценарием, как есть. Я добавил дополнительные операторы в ваш код, чтобы увидеть, что происходит:
#!/bin/bash
ps -H -o pid,ppid,sid,cmd
echo '$$' is $$
SID=`ps -p $$ --no-headers -o sid`
if [ $# -ge 1 -a $$ -ne $SID ] ; then
setsid bash test.sh
echo pid=$$ ppid=$PPID sid=$SID parent
else
sleep 2
echo pid=$$ ppid=$PPID sid=$SID child
sleep 2
fi
дело, которое касается вас:
./test.sh 1
и поверьте мне, запустите этот измененный скрипт, и вы увидите, что именно происходит. Если оболочка, которая не является лидером сеанса, запускает скрипт, то она просто переходит в else
заблокировать. Я что-то упускаю?
теперь я понимаю, что вы имеете в виду: когда вы делаете ./test.sh 1
С вашим скриптом как есть затем родитель ждет завершения ребенка. ребенок блокирует родителя. Но если вы запустите ребенка в фоновом режиме, вы заметите, что родитель завершает перед ребенком. Поэтому просто внесите это изменение в свой скрипт:
setsid bash test.sh &