Может кто-нибудь подробно объяснить, что делает «set -m»?

16

На странице руководства это просто говорит:

-m Управление заданиями включено.

Но что это на самом деле означает?

Я столкнулся с этой командой в одном вопросе , у меня та же проблема, что и у OP, а именно: "fabric не может запустить tomcat". И set -mрешил это. ОП объяснил немного, но я не совсем понимаю:

Проблема была в фоновых задачах, поскольку они будут убиты, когда команда закончится.

Решение простое: просто добавьте "set -m;" префикс перед командой.

laike9m
источник

Ответы:

10

Цитирование документации bash (из man bash):

JOB CONTROL
       Job  control  refers to  the  ability  to selectively  stop
       (suspend) the execution of  processes and continue (resume)
       their execution at a later point.  A user typically employs
       this facility via an interactive interface supplied jointly
       by the operating system kernel's terminal driver and bash.

Таким образом, проще говоря, наличие set -m(по умолчанию для интерактивных оболочек) позволяет использовать встроенные модули, такие как fgи bg, которые будут отключены в set +m(по умолчанию для неинтерактивных оболочек).

Однако для меня не очевидно, какова связь между управлением заданиями и уничтожением фоновых процессов при выходе, но я могу подтвердить, что есть одно: запуск set -m; (sleep 10 ; touch control-on) &создаст файл, если он выйдет из оболочки сразу после ввода этой команды, но set +m; (sleep 10 ; touch control-off) &не будет.

Я думаю, что ответ лежит в остальной документации для set -m:

-m      Monitor  mode. [...]                     Background pro‐
        cesses run in a separate process group and a  line  con‐
        taining  their exit status is printed upon their comple‐
        tion.

Это означает, что фоновые задания, запущенные под set +m, не являются фактическими «фоновыми процессами» («Фоновые процессы - это те, чей идентификатор группы процессов отличается от идентификатора терминала»): они имеют тот же идентификатор группы процессов, что и оболочка, которая их запустила, а не имеют свои собственные группа процессов, как правильные фоновые процессы. Это объясняет поведение, наблюдаемое при выходе из оболочки перед некоторыми из ее фоновых заданий: если я правильно понимаю, при выходе сигнал отправляется процессам в той же группе процессов, что и оболочка (таким образом, уничтожение фоновых заданий, запущенных в set +m), но не к тем из других групп процессов (таким образом, оставляя в покое истинные фоновые процессы, запущенные под set -m)

Итак, в вашем случае startup.shскрипт предположительно запускает фоновое задание. Когда этот сценарий выполняется неинтерактивно, например, через SSH, как в вопросе, с которым вы связаны, управление заданиями отключается, «фоновое» задание разделяет группу процессов удаленной оболочки и, таким образом, уничтожается при выходе из оболочки. И наоборот, включив управление заданиями в этой оболочке, фоновое задание получает свою собственную группу процессов и не уничтожается при выходе из родительской оболочки.

dhag
источник
Спасибо за ваш ответ, но как это tomcat/bin/startup.shсвязано с fg/ bg?
laike9m
1
Это не связано напрямую; Я пытался ответить "Управление заданиями включено / что это на самом деле означает?" в общем. Возможно, я не дал понять, но ваш сценарий, кажется, запускает фоновую работу, к которой относится остальная часть моего ответа.
Даг
2

Я нашел это в списке вопросов GitHub, и я думаю, что это действительно ответит на ваш вопрос.

На самом деле это не проблема SSH, это более тонкое поведение неинтерактивных / интерактивных режимов BASH и распространения сигналов в группы процессов.

Следующее основано на /programming/14679178/why-does-ssh-wait-for-my-subshells-without-t-and-kill-them-with-t/14866774#14866774 и http: //www.itp.uzh.ch/~dpotter/howto/daemonize , с некоторыми предположениями, не полностью проверенными, но тесты о том, как это работает, похоже, подтверждают.

pty / tty = false

Запущенная оболочка bash подключается к stdout / stderr / stdin запущенного процесса и продолжает работать до тех пор, пока к сокетам ничего не подключено и его дочерние элементы не завершены. Хороший процесс deamon гарантирует, что он не будет ждать, пока его дочерние элементы завершат работу дочернего процесса, а затем завершат работу. В этом режиме SSH не отправляет SIGHUP дочернему процессу. Я полагаю, что это будет работать правильно для большинства сценариев, выполняющих процесс, который выполняет деамонизацию сам по себе и не нуждается в фоновом режиме. В тех случаях, когда сценарии инициализации используют '&' для фонового процесса, вероятно, основная проблема будет в том, будет ли когда-либо фоновый процесс пытаться читать из stdin, так как это вызовет SIGHUP, если сеанс был завершен.

pty / tty = true *

Если сценарий инициализации служит фоном для запуска процесса, родительская оболочка BASH вернет код выхода в соединение SSH, которое, в свою очередь, будет ожидать немедленного завершения, поскольку не ожидает завершения дочернего процесса и не блокируется на stdout. / STDERR / STDIN. Это приведет к отправке SIGHUP в родительскую группу процессов оболочки bash, которая, поскольку управление заданиями отключено в неинтерактивном режиме в bash, будет включать только что запущенные дочерние процессы. Если процесс-демон явно запускает новый сеанс процесса при разветвлении или в разветвленном процессе, то он или его дочерние элементы не получат SIGHUP от выхода родительского процесса BASH. Обратите внимание, что это отличается от приостановленных заданий, которые будут видеть SIGTERM. Я подозреваю, что проблемы, связанные с этой единственной работой, иногда связаны с небольшим состоянием гонки. http://www.itp.uzh.ch/~dpotter/howto/daemonize , вы увидите, что в коде новый сеанс создается разветвленным процессом, который не может быть запущен до выхода из родительского процесса, что приводит к случайному поведение успех / неудача, упомянутое выше. Оператор сна даст достаточно времени для того, чтобы разветвленный процесс создал новый сеанс, поэтому он работает в некоторых случаях.

pty / tty = true и контроль заданий явно включен в bash

SSH не будет подключаться к stdout / stderr / stdin оболочки bash или любых запущенных дочерних процессов, что будет означать, что он завершится, как только родительская оболочка bash закончит выполнение запрошенных команд. В этом случае, при явном включении управления заданиями, любые процессы, запущенные оболочкой bash с '&' для их фоновой обработки, будут немедленно помещены в отдельный сеанс и не получат сигнал SIGHUP, когда родительский процесс в сеансе BASH завершится ( SSH соединение в этом случае).

Что нужно исправить

Я думаю, что решения должны быть явно упомянуты в документации по операциям run / sudo как особый случай при работе с фоновыми процессами / сервисами. В основном либо используйте 'pty = false', либо, если это невозможно, явно включите управление заданиями в качестве первой команды, и поведение будет правильным.

С https://github.com/fabric/fabric/issues/395

pootow
источник