Попытка закрыть все дочерние процессы, когда я прерываю мой скрипт
Я написал скрипт bash для проведения некоторых тестов в моей системе. Тесты проходят в фоновом режиме и параллельно. Тесты могут занять много времени, и иногда я могу прервать тестирование на полпути.
Если я удерживаю Control+C, то он прерывает родительский сценарий, но оставляет работающих детей. Я хочу сделать так, чтобы я мог нажать Control+C или иным образом выйти и затем убить все дочерние процессы, работающие в фоновом режиме. У меня есть немного кода, который выполняет эту работу, если я запускаю фоновые задания прямо из терминала, но в моем сценарии это не работает.
У меня есть минимальный рабочий пример.
Я пытался использовать trap в сочетании с pgrep -P $$.
#!/bin/bash
trap 'kill -n 2 $(pgrep -P $$)' 2
sleep 10 &
wait
Я надеялся, что при нажатии control+c (SIGINT) будет убито все, что запускается скрипт, но на самом деле он говорит:
./breakTest.sh: line 1: kill: (3220) - No such process
Это число меняется, но, похоже, оно не относится ни к каким запущенным процессам, поэтому я не знаю, откуда оно.
Я предполагаю, что если содержимое команды trap будет оцениваться там, где происходит команда trap, то это может объяснить результат. Pid 3220 может быть для самого pgrep.
Буду признателен за понимание
Спасибо
3 ответа
Я нашел решение с помощью pkill. Этот пример также имеет дело со многими дочерними процессами.
#!/bin/bash
trap 'pkill -P $$' SIGINT SIGTERM
for i in {1..10}; do
sleep 10 &
done
wait
Похоже, это элегантно убивает все дочерние процессы. Хотя я не совсем понимаю, в чем проблема с моим исходным кодом, кроме отправки правильного сигнала.
В Bash всякий раз, когда вы используете &
после команды она помещает эту команду в качестве фонового задания (эти фоновые задания называются job_spec), которое увеличивается на единицу до тех пор, пока вы не завершите сеанс терминала. Вы можете использовать jobs
команда, чтобы получить список запущенных фоновых заданий. Для работы с этой работой вы должны использовать %
с идентификатором работы. jobs
Команда также принимает другие параметры, такие как jobs -p
чтобы увидеть все процессы процессов, jobs -p %JOB_SPEC
чтобы увидеть процесс идентификации этой конкретной работы.
#!/usr/bin/env bash
trap 'kill -9 %1' 2
sleep 10 &
wait
или же
#!/usr/bin/env bash
trap 'kill -9 $(jobs -p %1)' 2
sleep 10 &
wait
Я реализовал что-то вроде этого несколько лет назад, вы можете взглянуть на это async bash
Вы можете попробовать что-то вроде следующего:
pkill -TERM -P <your_parent_id_here>