Запустите фоновый процесс из скрипта и управляйте им, когда скрипт закончится

15

Я хотел бы запустить и настроить процесс аналогично демону из скрипта.
Моя оболочка эмулируется Zsh под Cygwin, а демон - SFK , базовый FTP-сервер.

Что важно здесь, сценарий startserv.shможет быть составлен следующим образом:

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
$cmd &

После запуска сценария startserv.shон останавливается (заканчивается?), Не показывая никаких подсказок, затем:

  • CTRL+ Cзавершает как скрипт, так и процесс фоновой работы;

  • Удар Enterпо сценарию завершает процесс, остается в фоновом режиме.

В любом случае, я вижу это только через, psа не через jobs, поэтому, когда я хочу закрыть процесс, я должен послать жестокий kill -9сигнал, чего я хотел бы избежать в пользу CTRL+ C.

Альтернативой будет запуск всего скрипта в фоновом режиме. «Будет», но readкоманда не может получить пользовательский ввод, если скрипт запускается как startserv.sh &.

Обратите внимание, что мне нужен эфемерный сервер, а не настоящий демон : то есть я хочу, чтобы серверный процесс выполнялся в фоновом режиме, после завершения сценария, для выполнения простых задач интерактивной оболочки (с гостем виртуальной машины), но я не t нужен процесс, чтобы выжить в раковине; поэтому nohupкажется не уместным.

антонио
источник
получить идентификатор процесса, работающего в фоновом режиме, с помощью, bgproc="$!"а затем command "$bgproc" выполнить соответствующее действие. См. Также stackoverflow.com/questions/1908610/…
Валентин Байрами
Вы также можете сделать файл PID. Затем прочитайте этот файл, чтобы увидеть, что это за номер процесса, и перейдите оттуда.
jgr208

Ответы:

18

Удар Enterпо сценарию завершает процесс, остается в фоновом режиме.

Почти! На самом деле, сценарий уже завершился к тому времени, когда вы нажимаете Enter. Тем не менее, вы можете получить подсказку обратно (поскольку ваша оболочка печатает $PS1заново).

Причина, по которой нажатие Ctrl+ Cзавершает их обоих, заключается в том, что они оба связаны. Когда вы выполняете свой скрипт, ваша оболочка запускает подоболочку, в которой он запускается. Когда вы завершаете эту подоболочку, ваш фоновый процесс умирает, вероятно, от SIGHUPсигнала.

Отдельный скрипт, фоновый процесс и подоболочка

Используя nohup, вы сможете избавиться от этого небольшого неудобства.

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

disownальтернатива

Если вы можете переключиться с /bin/shна /bin/bash, вы также можете попробовать disown. Чтобы узнать больше, просто наберите help disownв bashэкземпляре.

disown -h $cmd &

Убить фоновый процесс "красиво"

Теперь, когда дело доходит до уничтожения вашего процесса, вы можете отлично использовать знак « Ctrl+ C» kill. Только не присылай жестокое SIGKILL. Вместо этого вы можете использовать:

$ kill -2 [PID]
$ kill -15 [PID]

Который отправит хороший SIGINT(2) или SIGTERM(15) в ваш процесс. Вы также можете распечатать значение PID после запуска процесса:

...
nohup $cmd &
echo $!

... или, что еще лучше, заставьте скрипт ждать a SIGINTи отправьте его обратно в фоновый процесс (это сохранит ваш скрипт на переднем плане) :

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

# Storing the background process' PID.
bg_pid=$!

# Trapping SIGINTs so we can send them back to $bg_pid.
trap "kill -2 $bg_pid" 2

# In the meantime, wait for $bg_pid to end.
wait $bg_pid

Если SIGINTне достаточно, просто используйте SIGTERMвместо (15):

trap "kill -15 $bg_pid" 2 15

Таким образом, когда ваш сценарий получает SIGINT( Ctrl+ C, kill -2) или SIGTERMвремя waitдля фонового процесса, он просто передает ему сигналы. Если эти сигналы уничтожат sfkэкземпляр, то waitвызов вернется, следовательно, и ваш скрипт завершится :)

Джон У. Смит
источник
1
+1 Очень информативно. Поскольку сценарий выполняется в подоболочке, есть ли возможность доступа из сценария к таблице заданий родительской оболочки сценария? То есть список заданий, выдаваемых jobsв терминале после завершения скрипта (а не ps).
Антонио
1
Задания связаны с вашей текущей оболочкой, они не передаются из одной оболочки в другую. Когда ваша подоболочка умирает, ее рабочие места не восстанавливаются. Распечатывая PID фонового процесса, вы гарантируете, что сможете легко получить информацию о нем даже после того, как подоболочка завершена ( pid -p).
Джон У. С. Смит,
хорошее объяснение, однако, если ваш скрипт содержит больше команд, они никогда не будут выполнены (из-за wait). Если убрать ожидание, то обработка сигнала нарушится: /
chefarov