Как мне отслеживать и уничтожать все процессы, порожденные запуском сценария, не зная имен подпроцессов?

У меня есть сценарий-оболочка Bash, который запускает сложный сценарий моделирования, который, в свою очередь, запускает несколько подпроцессов и собственных сценариев. Я хочу выяснить, как отслеживать все процессы, порождаемые одним запуском сценария моделирования, чтобы уничтожать их все при выполнении определенных критериев.

Например, мой скрипт-оболочка под названием pipeline_runner.sh делает следующее:

#!/bin/bash

# Some set up of the script ...

./monitor_job.sh ... arguments TBD ... &

script_path = "path/to/bash/script"

chmod u+x "$script_path"
"$script_path"

# ...

Каждый запуск pipeline_runner.sh запускает экземпляр monitor_job.sh в фоновом режиме для отслеживания конкретного запуска path/to/bash/script, запущенного этим запуском pipeline_runner.sh. Когда какое-то произвольное условие, определенное в monitor_job.sh, выполняется, оно должно иметь возможность уничтожить этот конкретный запуск path/to/bash/script вместе со всеми процессами, прямо или косвенно запущенными им.

Множество других процессов, запускаемых запуском path/to/bash/script, многочисленны и различаются, поэтому я пытаюсь выяснить, как захватить каждый скрипт, который создается в результате запуска, в какую-то группу или список и иметь возможность уничтожить их все, когда это необходимо. Уничтожить только начальный процесс $script_path недостаточно, поскольку все подпроцессы этого сценария сохранятся.

Важными второстепенными целями являются:

  • сделать эту динамику такой, чтобы она не зависела от того, какой сценарий обозначен $script_path. Это означает, что я не могу просто жестко закодировать конкретные имена команд для поиска.

  • осуществлять мониторинг в отдельном скрипте (monitor_job.sh), как описано, а не напрямую в pipeline_runner.sh.

Как я могу отслеживать все процессы, запускаемые скриптом моделирования, чтобы иметь возможность убить их все при необходимости?

🤔 А знаете ли вы, что...
Bash предоставляет мощные механизмы для автоматизации задач в командной строке.


3
58
1

Ответ:

Решено

kill -- -$$ завершит всю группу процессов.

Например, в следующем скрипте мы запускаем 2 подпроцесса, sleep 15 и sleep 30, тогда у нас могут быть другие задачи для запуска (в данном случае sleep 5), и поскольку мы удовлетворяем нашим критериям выхода, мы можем убить всю группу процессов.

#!/bin/sh
echo "Parent pid $$"
sleep 15 &
echo "child 1 pid $!"

sleep 30 &
echo "child 2 pid $!"

sleep 5
echo "criteria met"
kill -- -$$

Если мы запустим это с bash test.sh ; ps -ef | grep sleep, мы получим:

$ bash test.sh ;  ps -ef | grep sleep
Parent pid 87546
child 1 pid 87547
child 2 pid 87548
criteria met
Terminated: 15
  501 87595   789   0  2:08PM ttys007    0:00.00 grep sleep

Таким образом, мы видим, что подпроцессы также были убиты.

Проблема с этим подходом в том, что если бы сочетание клавиш Ctrl+C было введено сразу после моего выполнения, мы бы получили:

$ bash test.sh ;  ps -ef | grep sleep
Parent pid 88352
child 1 pid 88353
child 2 pid 88354
^C
  501 88353     1   0  2:10PM ttys007    0:00.00 sleep 15
  501 88354     1   0  2:10PM ttys007    0:00.00 sleep 30
  501 88391   789   0  2:10PM ttys007    0:00.00 grep sleep

Это означает, что различные подпроцессы будут продолжать работать как «сироты» (принятые процессом инициализации).

Чтобы решить эту проблему, мы могли бы использовать trap и изменить наш скрипт на:

#!/bin/sh

trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT

echo "Parent pid $$"

sleep 15 &
echo "child 1 pid $!"

sleep 30 &
echo "child 2 pid $!"

sleep 5
echo "criteria met"
exit 0

Обычное выполнение останется прежним, потому что exit 0 будет пойман ловушкой и, в свою очередь, kill -- -$$ будет выполнен, как и раньше.

Теперь, если мы запустим наш скрипт и введем ctrl+c сразу после выполнения, на этот раз мы получим:

Parent pid 91578
child 1 pid 91579
child 2 pid 91580
^CTerminated: 15
  501 91590   789   0  2:18PM ttys007    0:00.00 grep sleep

где мы видим, что подпроцесс также был убит.