предположим, я хочу запустить несколько (скажем, три) программ одновременно, как это
program1 & program2 & program3 &
Если я хочу знать их pid's
, я думаю, лучший способ — хранить их вот так
program1 &
pid1=$!
program2 &
pid2=$!
...
Но что теперь, если я хочу узнать, закончились ли они, и если да, то какое значение они вернули? Что-то вроде этого:
if [ program1 has ended ]; then
do something with its return value
fi
Любая помощь будет оценена по достоинству.
решение1
# launch child process in background
launch_child_process &
# grab child's pid and store it (use array if several)
pid=$!
# later, wait for termination
wait $pid
# show return code from wait, which is actually the return code of the child
echo "Child return code:" $?
С несколькими потомками вы, конечно, можете зацикливаться, чтобы ждать на каждом pid и собирать соответствующий код возврата. Вы выходите из этого цикла, когда последний потомок заканчивается.
решение2
Одним из простых решений является запись сообщения в файл журнала.
Скажем, для программы 1 сделайте что-то вроде:
#!/bin/bash
.
.
your stuff
.
.
end_time==$(date)
echo "program1 ended at $end_time" > program1_log
Другим решением было бы создание пустого файла, чтобы отметить окончание процесса.
#!/bin/bash
.
.
your stuff
.
.
echo $? > /some/path/program1_ended #storing the exit value
#disadvantage is that you can't verify if intermediate commands failed.
Затем, чтобы проверить, сделайте
if [ -e /some/path/program1_ended ]
then
exit_status=$( </some/path/program1_ended )
rm /some/path/program1_ended #Deleting the file, getting ready for next run
.
.
Do something
else
echo "program1 has not ended yet"
fi
решение3
POSIX sh не очень хорош в обработке нескольких фоновых процессов. Базовый инструмент — wait
встроенный, который блокирует до тех пор, пока фоновый процесс не завершится. Но wait
без аргумента ждет, покавсефоновые процессы завершились и возвращает статус завершения последнего завершившегося процесса; статус завершения других подпроцессов теряется.
Вы можете установить ловушку для SIGCHLD, который является сигналом, который выдается при завершении дочернего процесса. Это выполняет код при каждом завершении подпроцесса. Однако вы не обязательно узнаете, какой подпроцесс завершился или каков его статус возврата. Разные оболочки ведут себя по-разному.
ATT ksh93 (не mksh или pdksh!) — единственный из распространенных оболочек, который ведет себя полезно с ловушками SIGCHLD. Он устанавливает $!
PID процесса, который завершился, и $?
его статус возврата.
#!/bin/ksh
trap 'Process $! (${subprocesses[$!]}) exited with status $?' CHLD
typeset -A subprocesses
program1 & subprocesses[$!]='program1'
program2 & subprocesses[$!]='program2'
wait
Если вы используете другую оболочку, поместите всю последующую обработку в подпроцесс.
#!/bin/sh
{ program1; echo "program1 exited with status $?"; } &
{ program2; echo "program2 exited with status $?"; } &
wait
Или используйте более совершенный язык, такой как Perl, Python, Ruby и т. д.
решение4
Если вы знаете, в каком примерно порядке будут завершены процессы, вы можете использовать , wait <pid>
чтобы дождаться его завершения, и wait
команда унаследует статус завершения ожидаемого процесса. Например:
if wait $pid1
then echo "$pid1 was ok"
else echo "$pid1 failed with code $?"
fi
Если вы не знаете порядок, вы можете дождаться любого из них с помощью wait -n $pid1 $pid2 ...
и получить код завершения аналогичным образом, но вы не узнаете, какой именно процесс завершился, но это полезно, если вам просто нужно узнать, произошел ли сбой в каком-либо из них.