Как дождаться завершения всех порожденных и фоновых процессов в сценарии bash

Слово «онлайн» используется в смысле « работает под непосредственным управлением или подключением к главному компьютеру . " Таким образом, чтение руководства в интерактивном режиме - то же самое, что чтение его на компьютере.

Это контрастирует с «автономным» в смысле « работает независимо от связанного компьютера или отключен от него». Поэтому чтение руководства в автономном режиме - то же самое, что чтение его каким-либо другим способом, возможно, на бумаге (или спрашивая домашнего мастера, который знает каждое руководство наизусть).

3
16.01.2016, 22:50
3 ответа

Это будет истинно, если $ PID1 запущен: if [kill -s 0 $ PID1]

У вас может быть несколько предложений if. Они будут оценивать как ложь, если PID не работает. Этот пункт (в сочетании с другими) должен управлять потоком сценария по вашему желанию.

-1
27.01.2020, 21:46

Для каждой команды вы можете коснуться файла и проверить этот файл. Вот простой пример:

#!/usr/local/bin/bash

# Flag to knkow when completed
finished=0;

# The commands t run
declare -a commands=('cmd1' 'cmd2' 'cmd3' 'cmd4');

# Fork all commands
for cmd in "${commands[@]}"; do
        ./$cmd &
done

# Loop to wait for all processes to finish
loop=0;
while [ $finished -eq 0 ]; do
        # Just for visual effect
        loop=$((loop+1));
        echo "Loop $loop";
        sleep 1;

        files=0;
        for cmd in "${commands[@]}"; do
                # Each program shoudl touch a file so that we
                # can know it has completed successfully
                if [ -e ".$cmd" ]; then
                        echo "Process $cmd completed";
                        files=$((files+1));
                else
                        # No need to continue if anything is not done
                        # Error checking here like a TTL value or ps -ef | grep pid etc
                        echo "Waiting for process $cmd";
                        break;
                fi;
        done

        # if we have as many files as executed commands
        if [ "$files" -eq ${#commands[@]} ]; then
                finished=1;
        fi
done;

echo 'All jobs completed successfully';
# Clean up after yourself
for cmd in "${commands[@]}"; do
        rm -f ".$cmd";
done;

Тогда для проверки каждой команды cmd1, cmd2 ... cmdN может быть что-то вроде:

#!/usr/local/bin/bash
num=1;

echo "Enter cmd$num";
sleep 1; # use different sleep values to simulate execution
touch ".cmd$num"
echo "Exit cmd$num";
0
27.01.2020, 21:46

Сначала попробуйте более простой сценарий, например, только 2 процесса FOO1 и FOO2, и если бы вы запустили внутри сценария, например, с именем parent.sh:

#!/bin/bash

FOO1 &
pid1=$!

echo "Child PID=$pid1 launched"

FOO2 &
pid2=$!

echo "Child PID=$pid2 launched"

BAR exit FOO1
BAR exit FOO2

echo "Pausing to wait for children to finish..."

wait $pid1
wait $pid2

echo "Children finished, moving on."

Посмотрите, работает ли это с двумя FOOs, и если да, то реализуйте для 20.

Пояснение

Поскольку мы не можем видеть внутреннее устройство FOOs и BAR процесса, я полагаюсь только на то, что вы опубликовали, и, как я понимаю, вы сказали

  • "Процесс BAR используется для проверки FOO и также используется для его уничтожения"
  • означает, в какой-то момент до опубликованного вами сниппета вы запустили FOO1 каким-то образом, чтобы BAR exit FOO1 повлиял на него

Среди вашего первоначально опубликованного сниппета, вы также написали:

BAR exit FOO1
PID1=$!
  • $! захватывает самый последний процесс, находящийся в фоновом режиме
  • но BAR exit FOO1 не является процессом, уходящим в фон, это, как вы утверждаете, средство использования BAR для управления FOO: "BAR используется для проверки FOO, а также используется для его убийства"
  • таким образом $! вряд ли будет перехватывать pid FOO1

Поэтому вместо этого убедитесь, что прямо там, где вы действительно запускаете процесс FOO*, вы перехватываете pid. Например, если вы запускаете все в parent. sh, и у вас только 2 процесса, вы сделаете следующее:

#!/bin/sh

FOO1 &
pid1=$!

echo "Child PID=$pid1 launched"

FOO2 &
pid2=$!

echo "Child PID=$pid2 launched"
  • строчные pid1, вы можете использовать и прописные буквы, лишь бы они были последовательными, я предпочитаю использовать строчные буквы, чтобы не перепутать их с переменными окружения
  • echo - это необязательная трассировка, чтобы мы знали, что происходит, используйте его во время поиска неисправностей и закомментируйте его с помощью # или удалите его, как только решите проблему

Затем мы выполняем команды, которые, как вы утверждали, вы используете для проверки и убиваем FOO1 и FOO2:

BAR exit FOO1
BAR exit FOO2

Затем,

echo "Pausing to wait for children to finish..."

wait $pid1
wait $pid2

echo "Children finished, moving on."
  • снова echo- необязательные, но информативные, пока вы все еще устраняете неполадки, позволяющие нам знать, что происходит
  • wait для каждого отдельного $pid. ..
  • затем следует еще одно необязательное echo, чтобы сообщить, что ожидание закончилось

CREDIT

Shotts 2009 пример асинхронных скриптов на странице 506 бесплатного pdf

0
27.01.2020, 21:46

Теги

Похожие вопросы