Якщо якісь спарені дочірні процеси провалюються, вбийте всіх і вийдіть


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 всім членам поточної групи процесів.


В баш. Чому я включив шебанг - потрібна оболонка не зрозуміла. Гарна відповідь
jim mcnamara

@jimmcnamara, що працює в bash, dash, yash, mksh, zsh. В основному будь-яка оболонка POSIX, але AT&T ksh. set -mвказано (недостатньо) в POSIX, але як додаткова функція.
Стефан Шазелас

Я використовую Solaris. / бін / ш не полетить.
jim mcnamara

@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як початимуться всі інші, можливо, вони не містять усіх підручників, які були розпочаті.
Стефан Шазелас

Кілька поганих практик, таких як змінні, які не котируються, використання сигнальних номерів замість імен, використання сигналу 6 (наприклад, ABRT на Linux amd64) замість USR1 / USR2 як сигнал користувача, [ $? -ne 0 ]...
Stéphane Chazelas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.