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 &