Если какой-либо порожденный дочерний процесс завершится неудачно, убейте все и выйдите

9

В моем скрипте я разделил набор данных на input_aa, input_ab и т. Д. Затем я запускаю каждый из них по одному и тому же скрипту Python:

# Execute program on each split file
for part in input_*; do
        python3 $part &
done
wait

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

случаться
источник

Ответы:

10

Вы можете использовать группу процессов:

set -m
(
   for part in input_*; do
     (python3 "$part" || kill 0) &
   done
   wait
)

set -m(и необязательная функция оболочки POSIX, необходимая функция оболочки Unix) запускает задания в своей собственной группе процессов. В bash, yash, zsh, mksh, это рабочие места подоболочку где set -mвключена поэтому внешний (...)и все процессы , созданные в пределах , которые будут размещены в той же самой группе процесса.

Для оболочек dashи для других ashоснованных оболочек это работает только в процессе оболочки верхнего уровня. Так что этот код будет работать, если он не вложен в подоболочку.

Это не будет работать в AT & T kshили старой оболочке SysV / Bourne.

kill 0 отправляет сигнал SIGTERM всем членам текущей группы процессов.

Стефан Шазелас
источник
В баш. Почему я включил шебанг - требуемая оболочка не понятно. Хороший ответ
Джим Макнамара
@jimmcnamara, что работает в bash, dash, yash, mksh, zsh. В основном любая оболочка POSIX, кроме AT & T ksh. set -mуказывается (недостаточно) в POSIX, но в качестве дополнительной функции.
Стефан Шазелас
Я использую Солярис. / bin / sh не будет летать.
Джим Макнамара
@jimmcnamara, no / bin / sh в Solaris 10 и более ранних версиях - это оболочка Bourne (не оболочка POSIX), а в 11 - AT & T ksh. Как я уже сказал, он работает в bash, dash, yash, mksh, zsh.
Стефан Шазелас
1
@mikeserv, который переопределяет процесс в 1, но не выводит его из группы процессов. kill 0убивает всех членов группы процессов независимо от их родителей. Смотрите, ps -jчтобы увидеть идентификаторы группы процессов.
Стефан Шазелас
3

Это пример. ИГРАТЬ с этим первым, чтобы получить именно то, что вам нужно. Это не может сломать много, как есть.

#!/bin/bash
# Example of killing off all children

> killfile
> outfile.err
kill_em()
{
   echo 'killing all children ' > 2
   while read pid
   do
      kill -0 $pid && kill -9 $pid  # if still running kill it
   done < killfile
   exit 1
}

export grandparentpid=$$
trap 'kill_em' 6
for i in 2 2 3 4 5 6 7 8 9 10
do
        ( sleep $i && ls oinkle  >> outfile 2>> outfile.err &
          pid=$!
          echo $pid >> killfile
          wait $!
          [ $? -ne 0 ] && kill -6 $grandparentpid
        ) &
done
wait

Это настроение для преднамеренного сбоя, потому что ls oinkleпроизойдет сбой (на моей машине).

Когда вы получите то, что вам нужно после работы со стартовым скриптом --- Изменить:

for i in 2 2 3 4 5 6 7 8 9 10

чтобы:

for part in input_* 

изменение:

sleep $i && ls oinkle 

чтобы:

python3 $part 

Перенаправления для сохранения журналов. Вы можете не хотеть их.

Джим Макнамара
источник
Это немного круто. Если одно из заданий не будет выполнено до того, killfileкак начнутся все остальные, то вы можете не содержать все pid заданий, которые были запущены.
Стефан Шазелас
Несколько плохих практик, таких как: переменные без кавычек, использование номеров сигналов вместо имен, использование сигнала 6 (например, ABRT в Linux amd64) вместо USR1 / USR2 в качестве пользовательского сигнала, [ $? -ne 0 ]...
Стефан Шазелас