Завершить выполнение команд при уничтожении оболочки script
В целях тестирования у меня есть эта оболочка script
#!/bin/bash
echo $$
find / >/dev/null 2>&1
Запустив это из интерактивного терминала, ctrl + c завершит bash и команду find.
$ ./test-k.sh
13227
<Ctrl+C>
$ ps -ef |grep find
$
Запустив его в фоновом режиме, и убить оболочку будет только сиротом команд, запущенных в script.
$ ./test-k.sh &
[1] 13231
13231
$ kill 13231
$ ps -ef |grep find
nos 13232 1 3 17:09 pts/5 00:00:00 find /
$
Я хочу, чтобы эта оболочка script завершала все свои дочерние процессы, когда она выходила, независимо от того, как она вызвана. В конце концов, это будет запущено из приложения python и java, и при выходе script необходимо выполнить какую-либо очистку - какие-либо параметры, которые я должен изучить, или каким-либо образом переписать script, чтобы очистить себя при выходе?
Ответы
Ответ 1
Я бы сделал что-то вроде этого:
#!/bin/bash
trap : SIGTERM SIGINT
echo $$
find / >/dev/null 2>&1 &
FIND_PID=$!
wait $FIND_PID
if [[ $? -gt 128 ]]
then
kill $FIND_PID
fi
Некоторые объяснения в порядке, я думаю. Из затвора нам нужно изменить часть обработки сигнала по умолчанию. :
- это команда no-op, так как передача пустой строки заставляет оболочку игнорировать сигнал вместо того, чтобы что-то делать (противоположное тому, что мы хотим сделать).
Затем команда find
запускается в фоновом режиме (с точки зрения script), и мы вызываем ее wait
для ее завершения. Поскольку мы дали реальную команду trap
выше, когда обрабатывается сигнал, wait
выйдет со статусом больше 128. Если процесс wait
ed для завершения, wait
вернет статус завершения этого процесс.
Наконец, если wait
возвращает этот статус ошибки, мы хотим kill
дочерний процесс. К счастью, мы сохранили свой PID. Преимущество этого подхода заключается в том, что вы можете зарегистрировать некоторое сообщение об ошибке или иначе идентифицировать, что сигнал вызвал выход script.
Как уже упоминалось, размещение kill -- -$$
в качестве аргумента trap
- это еще один вариант, если вы не хотите оставлять информацию о post-exit.
Чтобы trap
работал так, как вам нужно, вам нужно соединить его с wait
- на странице bash
говорит: "Если bash
ждет завершения команды и получает сигнал для который был установлен trap
, trap
не будет выполняться до тех пор, пока команда не завершится." wait
- это путь вокруг этой икоты.
Вы также можете расширить его на другие дочерние процессы, если хотите. Я действительно не исчерпывающе проверял это, но, похоже, он работает здесь.
$ ./test-k.sh &
[1] 12810
12810
$ kill 12810
$ ps -ef | grep find
$
Ответ 2
Ищет элегантное решение этой проблемы и нашел следующее решение в другом месте.
trap 'kill -HUP 0' EXIT
В моих собственных страницах о человеке ничего не говорится о том, что означает 0
, а от копания, похоже, это текущая группа процессов. Поскольку script получает свою собственную группу процессов, это заканчивает отправку SIGHUP всем дочерним элементам script, переднему и второму.
Ответ 3
Отправьте сигнал группе.
Поэтому вместо kill 13231
выполните:
kill -- -13231
Если вы начинаете с python, то посмотрите:
http://www.pixelbeat.org/libs/subProcess.py
который показывает, как имитировать оболочку при запуске
и убивая группу
Ответ 4
Просто добавьте такую строку в свой script:
trap "kill $$" SIGINT
Вам может потребоваться изменить "SIGINT" на "INT" в вашей настройке, но это приведет к потере вашего процесса и всех дочерних процессов при нажатии Ctrl-C.
Ответ 5
@Ответ Patrick почти сделал трюк, но он не работает, если родительский процесс вашей текущей оболочки находится в одной группе (он также убивает родителя).
Я нашел, что это лучше:
trap 'pkill -P $$' EXIT
Подробнее см. здесь.
Ответ 6
То, что вам нужно сделать, это ловушка сигнала уничтожения, убить команду find и выйти.