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 &