У меня есть сценарий bash, который запускает дочерний процесс, который время от времени завершается сбоем (фактически зависает) без видимой причины (с закрытым исходным кодом, поэтому я ничего не могу с этим поделать). В результате я хотел бы иметь возможность запускать этот процесс в течение определенного периода времени и завершать его, если он не завершился успешно через определенное время.
Есть ли простой и надежный способ добиться этого с помощью bash?
PS: скажите, подходит ли этот вопрос лучше для serverfault или superuser.
Ответы:
(Как видно из записи BASH FAQ # 68: «Как запустить команду и отменить ее (время ожидания) через N секунд?» )
Если вы не возражаете против загрузки чего-либо, используйте
timeout
(sudo apt-get install timeout
) и используйте это так: (в большинстве систем это уже установлено, в противном случае используйтеsudo apt-get install coreutils
)Если вы не хотите что-то скачивать, делайте то, что делает внутреннее время:
В случае, если вы хотите сделать тайм-аут для более длинного кода Bash, используйте второй параметр как таковой:
источник
cmdpid=$BASHPID
не возьмет pid вызывающей оболочки, а (первую) подоболочку, которая запущена()
. Эта(sleep
штука вызывает второй подоболочек в первом подоболочке, чтобы подождать 10 секунд в фоновом режиме и убить первый подоболочек, который после запуска процесса подоболочки-убийцы продолжает выполнять свою рабочую нагрузку ...timeout
является частью GNU coreutils, поэтому должен быть уже установлен во всех системах GNU.timeout
руководства ) , теперь является частью coreutils.или также получить коды выхода:
источник
kill -9
прежде чем попробовать сигналы, которые процесс может обработать в первую очередь.dosmth
в течение 2 секунд завершится, другой процесс получит старый pid, а вы убьете новый?источник
sleep 999
здесь) часто завершается быстрее, чем навязанный сон (sleep 10
)? Что если я хочу дать ему шанс до 1 минуты 5 минут? Что, если у меня в сценарии будет куча таких случаев :)У меня также был этот вопрос и я нашел еще две очень полезные вещи:
Поэтому я использую что-то вроде этого в командной строке (OSX 10.9):
Поскольку это цикл, я включил «0.2 сна», чтобы процессор остыл. ;-)
(Кстати: ping - плохой пример в любом случае, вы просто использовали бы встроенную опцию -t (timeout).)
источник
Предполагая, что у вас есть (или вы можете легко создать) файл pid для отслеживания pid ребенка, вы можете затем создать сценарий, который проверяет время изменения файла pid и при необходимости убивает / запускает процесс. Затем просто поместите скрипт в crontab, чтобы он выполнялся примерно в нужный период.
Дайте мне знать, если вам нужно больше деталей. Если это не похоже на то, что вам нужно, как насчет выскочки?
источник
Одним из способов является запуск программы в подоболочке и связь с подоболочкой через именованный канал с помощью
read
команды. Таким образом, вы можете проверить состояние выхода запускаемого процесса и сообщить об этом через канал.Вот пример тайм-аута
yes
команды через 3 секунды. Он получает PID процесса, который используетсяpgrep
(возможно, работает только в Linux). Существует также некоторая проблема с использованием канала в том, что процесс, открывающий канал для чтения, будет зависать до тех пор, пока он не будет открыт для записи, и наоборот. Поэтому, чтобы предотвратитьread
зависание команды, я «заклинил» открытие канала для чтения с помощью фоновой подоболочки. (Еще один способ предотвратить остановку, чтобы открыть канал чтения-записи, т.read -t 5 <>finished.pipe
Е., Однако, это также может не работать, кроме как с Linux.)источник
Вот попытка избежать попытки завершить процесс после того, как он уже завершился, что уменьшает вероятность уничтожения другого процесса с тем же идентификатором процесса (хотя, вероятно, невозможно полностью избежать такого рода ошибок).
Используйте лайк
run_with_timeout 3 sleep 10000
, который запускается,sleep 10000
но заканчивается через 3 секунды.Это похоже на другие ответы, которые используют фоновый процесс тайм-аута, чтобы убить дочерний процесс после задержки. Я думаю, что это почти то же самое, что расширенный ответ Дэна ( https://stackoverflow.com/a/5161274/1351983 ), за исключением того, что оболочка тайм-аута не будет уничтожена, если она уже закончилась.
После того, как эта программа закончилась, все еще будет несколько запущенных «спящих» процессов, но они должны быть безвредными.
Это может быть лучшим решением, чем мой другой ответ, потому что он не использует функцию непереносимой оболочки
read -t
и не используетpgrep
.источник
(exec sh -c "$*") &
аsh -c "$*" &
? В частности, зачем использовать первое вместо второго?Вот третий ответ, который я представил здесь. Этот обрабатывает прерывания сигнала и очищает фоновые процессы при
SIGINT
получении. Он использует$BASHPID
иexec
трюк , используемый в верхнем ответе , чтобы получить PID процесса (в данном случае$$
вsh
вызове). Он использует FIFO для связи с подоболочкой, которая отвечает за убийство и очистку. (Это похоже на канал в моем втором ответе , но наличие именованного канала означает, что обработчик сигнала также может писать в него.)Я старался избегать условий гонки, насколько смог. Тем не менее, один из источников ошибок, которые я не смог удалить, - это когда процесс заканчивается примерно в то же время, что и время ожидания. Например,
run_with_timeout 2 sleep 2
илиrun_with_timeout 0 sleep 0
. Для меня последнее дает ошибку:как он пытается убить процесс, который уже вышел сам по себе.
источник