Я бы запустил 2 процесса и заставил их записать в общий именованный канал после их завершения.Чтение из именованного канала является операцией блокировки, поэтому вам не нужны смешные инструкции sleep
внутри цикла.Это будет:
#!/usr/bin/env bash
mkfifo /tmp/run-checker
(./sleep60.sh ; echo 0 > /tmp/run-checker) &
(./sleep10.sh ; echo 1 > /tmp/run-checker) &
read line </tmp/run-checker
printf "Process %d finished earlier\n" "$line"
rm /tmp/run-checker
kill -- -$$
sleep60.sh:
#!/usr/bin/env bash
sleep 60
sleep10.sh:
#!/usr/bin/env bash
sleep 10
РЕДАКТИРОВАТЬ:
Если вы собираетесь вызывать скрипт из скрипта Python следующим образом:
#!/usr/bin/env python3
import os
os.system("./parallel.sh")
print("Done")
вы получите:
Process 1 finished earlier
./parallel.sh: line 11: kill: (-13807) - No such process
Done
Это потому, что kill -- -$$
пытается отправитьTERM сигнализирует группе процессов, как указано в man 1 kill
:
-n
, где n больше 1. Все процессы в группе процессов n сигнализируются.Когда задан аргумент в форме '-n', и он предназначен для обозначения группы процессов, либо сначала должен быть указан сигнал, либо перед аргументом должна стоять опция '-', в противном случае он будет приняткак сигнал для отправки.
Работает, когда вы запускаете параллельный.sh из терминала, потому что $$ - это PID подоболочки, а также группы процессов.Я использовал его, потому что очень удобно убивать61.pro, process0 или process1 и всех их детей за один раз.Тем не менее, при вызове parallel.sh из скрипта Python $$
больше не обозначает группу процессов и kill --
завершается неудачей.
Вы можете изменить файл parallel.sh следующим образом:
#!/usr/bin/env bash
mkfifo /tmp/run-checker
setsid bash -c "./sleep60.sh ; echo 0 > /tmp/run-checker" &
pid0=$!
setsid bash -c "./sleep10.sh ; echo 1 > /tmp/run-checker" &
pid1=$!
read line </tmp/run-checker
printf "Process %d finished earlier\n" "$line"
rm /tmp/run-checker
eval kill -- -\$"pid$((line ^ 1))"
Теперь он будет работать и при вызове из скрипта Python.Последняя строка
eval kill -- -\$"pid$((line ^ 1))"
убивает pid0, если pid1 завершил ранее, или pid0, если pid1 завершил ранее, используя двоичный оператор ^ для преобразования 0 в 1 и наоборот.Если вам это не нравится, вы можете использовать более подробную форму:
if [ "$line" -eq "$pid0" ]
then
echo kill "$pid1"
kill -- -"$pid1"
else
echo kill "$pid0"
kill -- -"$pid0"
fi