Почему setsid не может выйти из сценария оболочки?

$ cat test1.sh
#!/bin/bash

setsid sleep 100

Сценарий оболочки 'test1.sh' не завершится сразу.

$ cat test2.sh
#!/bin/bash

setsid sleep 100 &

Сценарий оболочки 'test2.sh' завершится сразу.

Может ли кто-нибудь объяснить для меня? Большое спасибо.

2 ответа

Вопрос, вероятно, является дубликатом этого еще более старого вопроса, и ответ там весьма полезен. Возможно, их следует объединить.

Меня тоже удивило такое поведение. Итак, я проверил справочную страницу:

      DESCRIPTION
       setsid runs a program in a new session. The command calls fork(2) if already a
       process group leader. Otherwise, it executes a program in the current process.
       This default behavior is possible to override by the --fork option.

Некоторый жаргон, чтобы понять здесь. Давайте проверим список определений POSIX (глава 3).

Сеанс это:

Набор групп процессов, созданных для целей управления заданиями. Каждая группа процессов является членом сеанса. Процесс считается членом сеанса, членом которого является его группа процессов. Вновь созданный процесс присоединяется к сеансу своего создателя. Процесс может изменить свое членство в сеансе; см. setsid(). В одном сеансе может быть несколько групп процессов.

The fork()call создает новый процесс, копируя текущий процесс. Больше информации в этом посте.

Лидер группы процессов:

Процесс, идентификатор процесса которого совпадает с идентификатором его группы процессов.

Так, setsidсоздаст новый процесс только в том случае, если он выполняется в качестве лидера группы процессов. Это всегда имеет место при запуске команды непосредственно в оболочке, поэтому очередь заданий может быть построена в виде списка групп процессов. Однако при запуске в составе сценария лидером группы является новый процесс оболочки, используемый для запуска сценария.

К счастью, у нас есть --forkвозможность принудительного создания нового процесса. Например, сценарий оболочки:

      #!/bin/sh
setsid --fork sleep 5

выйдет, не дожидаясь завершения, и sleepКоманда будет продолжаться, даже если вы закроете оболочку, из которой был запущен скрипт. Насколько мне известно, setsid --forkэто единственный способ убедиться, что команда выполняется как отдельный процесс .

Другие источники:

Ваш первый скрипт ждет setsid sleep 100 быть завершенным и затем возвращаемым (другими словами, он вернется после завершения сна, 100 секунд здесь), но 2-й сценарий не ожидает завершения команды, потому что & переводит команду в фоновый режим и возвращает сразу. Цитировать man bash:

If  a  command is terminated by the control operator &, the shell executes the
command in the background in a subshell. The shell does not wait for the command
to finish, and the return status is 0.

Также обратите внимание, что & является оператором управления и имеет более высокий приоритет. Надеюсь это поможет!

Другие вопросы по тегам