2009-10-29 3 views
13

Для тестирования у меня есть этот сценарий оболочкиTerminate выполнение команд, когда сценарий оболочки убита

#!/bin/bash 
echo $$ 
find/>/dev/null 2>&1 

Запуск этого из интерактивного терминала, Ctrl + C прекращает Баш, и команда поиска.

$ ./test-k.sh 
13227 
<Ctrl+C> 
$ ps -ef |grep find 
$ 

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

$ ./test-k.sh & 
[1] 13231 
13231 
$ kill 13231 
$ ps -ef |grep find 
nos 13232  1 3 17:09 pts/5 00:00:00 find/
$ 

Я хочу, чтобы этот скрипт оболочки завершал все его дочерние процессы, когда он выходит, независимо от того, как он вызывается. В конце концов, это будет запущено из приложения python и java, и при выходе скрипта потребуется какая-то форма очистки - какие-либо параметры, которые я должен изучить, или каким-либо образом переписать сценарий, чтобы очистить себя при выходе?

ответ

15

I Would что-то вроде этого:

#!/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 запускается в фоновом режиме (с точки зрения сценария), и мы вызываем для нее завершение wait. Так как мы дали реальную команду trap выше, когда обрабатывается сигнал, wait выйдет со статусом больше 128. Если процесс завершен, то вернет статус выхода этого процесса.

Последнее, если wait возвращает этот статус ошибки, мы хотим, чтобы kill был дочерним процессом. К счастью, мы сохранили свой PID. Преимущество этого подхода заключается в том, что вы можете зарегистрировать некоторое сообщение об ошибке или иначе определить, что сигнал заставил сценарий выйти.

Как уже упоминалось, помещение kill -- -$$ в качестве аргумента в trap - это еще один вариант, если вам не нужно оставлять информацию о выходе после выхода.

Для trap работать так, как вы хотите, вы должны соединить его с wait - страница bash человек говорит: «Если bash ждет команды для завершения и принимает сигнал, для которого trap был установлен, trap не будет выполняться, пока команда не завершится. " wait - это путь вокруг этой икоты.

Вы также можете расширить его до более детальных процессов, если хотите. Я на самом деле не исчерпывающе проверял это, но, похоже, здесь работает.

$ ./test-k.sh & 
[1] 12810 
12810 
$ kill 12810 
$ ps -ef | grep find 
$ 
+1

Обычная команда no-op - '': '". – ephemient

+0

Горячий. Теперь меняем. –

+0

Если я запускаю процесс в фоновом режиме, он не будет убит. Если я не запустил его в фоновом режиме, порожденный дочерний процесс будет убит –

0

То, что вам нужно сделать, это захватить сигнал убить, убить команду find и выйти.

+3

'kill' отправляет' SIGTERM' по умолчанию. 'SIGKILL' является непривлекательным. –

1

Просто добавьте такую ​​строку в скрипт:

trap "kill $$" SIGINT 

Вы, возможно, потребуется изменить «SIGINT» на «INT» на вашей установке, но это будет в основном убить процесс и все дочерние процессы, когда вы нажмите Ctrl-C.

+2

вместо 'kill $$', вы, вероятно, должны отправить TERM в pid команды find! –

+1

'$!' Возможно, хотя вы, вероятно, хотите более тонкий контроль, чем это. – ephemient

6

Отправьте сигнал группе. Таким образом, вместо kill 13231 сделать:

kill -- -13231 

Если вы начинаете с питоном затем посмотреть на: http://www.pixelbeat.org/libs/subProcess.py , который показывает, как имитировать оболочки в стартовом и убивает группу

+0

Будет ли каждая команда этого скрипта принадлежать к этой группе процессов? – nos

+0

Если вы начали с оболочки, да, в противном случае вам нужно будет начать, как это сделано в subProcess.py – pixelbeat

+0

У вас не всегда есть контроль над тем, как ваши скрипты будут прекращены. – ndemou

7

Ищет элегантное решение этой проблемы и нашел следующее решение в другом месте.

trap 'kill -HUP 0' EXIT 

Мои собственные страницы человек ничего не говорят о том, что 0 средства, но рыть вокруг, кажется, означает текущую группу процессов. Поскольку скрипт get имеет собственную группу процессов, это заканчивает отправку SIGHUP всем детям сценария, переднему и второму.

+0

Кажется, что это хорошо работает (попробовал убить скрипт ctrl-C и закрыть терминал), но я боюсь скрытых недостатков. Любой баш-гуру, желающий поделиться своим мнением? – ndemou

+0

http://stackoverflow.com/a/22644006/301717 предлагает аналогичный ответ, но кажется более надежным – Jezz

1

@ ответ Патрика почти сделал трюк, но он не работает, если родитель процесс вашего текущей оболочки находится в той же группе (она убивает родителей тоже).

Я нашел, что это будет лучше:

trap 'pkill -P $$' EXIT

Смотрите here для получения дополнительной информации.

Смежные вопросы