Убить выполняющийся shell-скрипт и завершить все процессы, работающие в нем.

Вопрос или проблема

У меня есть оболочка, работающая в фоновом режиме, которая запускает 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
Объяснение кода
  1. Управление фоновыми задачами: С помощью команды set -m вы включаете поддержку фоновых задач, что позволяет выполнять команды в фоне.

  2. Массив bgpids: Этот массив используется для хранения PID всех задач, выполняющихся в фоне.

  3. Функция cleanup: При вызове этой функции будет происходить попытка завершить все задачи, PID которых хранятся в массиве bgpids. Используется kill -9, чтобы принудительно завершить процессы (хотя это не всегда рекомендуется, лучше использовать kill без -9, позволяя процессам корректно завершиться).

  4. Обработчик сигналов: Команда trap устанавливает функцию cleanup для вызова при получении сигналов SIGINT (обычно вызывается при нажатии Ctrl+C) и SIGTERM (стандартный сигнал завершения).

  5. Цикл по задачам: Скрипт запускает 5 участников (JOB1, JOB2, JOB3, JOB4, JOB5) в фоне и сохраняет их PIDs в массиве.

  6. Ожидание завершения: Команда wait позволяет основному скрипту дожидаться завершения всех фоновых процессов.

Заключение

Используя описанный выше код, вы сможете эффективно управлять фоновыми процессами, гарантируя их полное завершение при убийстве основного скрипта. Этот подход делает ваш скрипт более надежным и управляемым, что особенно важно в сценариях автоматизации и управления задачами в системах Linux/Unix.

Оцените материал
Добавить комментарий

Капча загружается...