Вопрос или проблема
У меня есть оболочка, работающая в фоновом режиме, которая запускает 5 различных заданий.
Когда я запускаю скрипт оболочки, все 5 заданий начинают выполняться по порядку. Когда я убиваю эту оболочку, любой процесс, который работает, продолжает выполняться, даже если я убил оболочку.
$ bash shell.sh & echo $!
Это дает мне PID оболочки, что позволяет мне убить её позже, если я захочу сделать это в какой-то момент.
#!/bin/bash
JOB1
JOB2
JOB3
JOB4
JOB5
Как я могу заставить оболочку убить все процессы, работающие внутри, после ее завершения?
#!/bin/bash
set -m
declare -a bgpids
cleanup() {
for pid in "${bgpids[@]}"; do
kill -9 "$pid"
done
}
trap "cleanup" SIGINT SIGTERM
sometask &
bgpids+=("$!")
Ответ или решение
Убийство выполняющегося скрипта и всех процессов внутри него
Если у вас есть сценарий оболочки (shell script), который запускает несколько задач последовательно, и вы хотите, чтобы все эти задачи завершались одновременно с убийством основного скрипта, вам нужно реализовать механизм контроля за дочерними процессами.
Проблема
Как указано в вашем вопросе, когда вы убиваете основной скрипт, дочерние процессы продолжают выполняться, поскольку они не находятся под контролем killed-скрипта. Чтобы устранить эту проблему, вам нужно добавить обработчик сигналов и механизм для отслеживания и завершения дочерних процессов.
Решение
Существует несколько способов обеспечить завершение всех дочерних процессов при убийстве основного скрипта. Рассмотрим один из наиболее эффективных вариантов, использующий команды trap
и kill
.
Пример реализации
Ниже приведен пример скрипта, в котором реализовано данное решение. Этот скрипт отслеживает идентификаторы процессов (PID) всех запущенных задач и завершает их при получении сигнала:
#!/bin/bash
# Включаем возможность фоновых задач
set -m
# Объявляем массив для хранения PIDs фоновых задач
declare -a bgpids
# Функция очистки
cleanup() {
echo "Завершение всех задач..."
for pid in "${bgpids[@]}"; do
kill -9 "$pid" 2>/dev/null
done
exit 0
}
# Установка обработчиков сигналов (SIGINT и SIGTERM) для выполнения функции cleanup
trap "cleanup" SIGINT SIGTERM
# Пример выполнения различных задач
for job in JOB1 JOB2 JOB3 JOB4 JOB5; do
$job & # Запустите задачу в фоновом режиме
bgpids+=("$!") # Сохраните PID задачи в массив
done
# Ожидание завершения всех фоновых процессов
wait
Объяснение кода
-
Управление фоновыми задачами: С помощью команды
set -m
вы включаете поддержку фоновых задач, что позволяет выполнять команды в фоне. -
Массив
bgpids
: Этот массив используется для хранения PID всех задач, выполняющихся в фоне. -
Функция
cleanup
: При вызове этой функции будет происходить попытка завершить все задачи, PID которых хранятся в массивеbgpids
. Используетсяkill -9
, чтобы принудительно завершить процессы (хотя это не всегда рекомендуется, лучше использоватьkill
без-9
, позволяя процессам корректно завершиться). -
Обработчик сигналов: Команда
trap
устанавливает функциюcleanup
для вызова при получении сигналовSIGINT
(обычно вызывается при нажатии Ctrl+C) иSIGTERM
(стандартный сигнал завершения). -
Цикл по задачам: Скрипт запускает 5 участников (JOB1, JOB2, JOB3, JOB4, JOB5) в фоне и сохраняет их PIDs в массиве.
-
Ожидание завершения: Команда
wait
позволяет основному скрипту дожидаться завершения всех фоновых процессов.
Заключение
Используя описанный выше код, вы сможете эффективно управлять фоновыми процессами, гарантируя их полное завершение при убийстве основного скрипта. Этот подход делает ваш скрипт более надежным и управляемым, что особенно важно в сценариях автоматизации и управления задачами в системах Linux/Unix.