Intereting Posts
Как я могу создать цикл for, запускающий множество процессов? Как использовать открытый ключ для входа в SSH лучше, чем использование пароля? SmartMonTools: Как узнать, есть ли какой-либо тест smartctl на моем жестком диске? службы тестирования / открытые порты с telnet? Подключить с помощью sshfs и записать разрешения на файл Значение chmod 1775 Как запустить скрипт после входа в систему с помощью gdm? Как избавиться от нежелательного входного повторяющегося пояса? найти все каталоги (кроме «закодированных») в рабочем каталоге, а затем удалить все из них Wicd не может обнаружить беспроводные сети при тестировании Debian 6, Xfce, новой установке Дата «1 месяц назад» не работает в AIX человек игнорирует псевдоним Как я могу заставить chrooted программы использовать виртуальное устройство Ethernet? Зависимость ад: почему бы не создавать переносные приложения rsync поддерживать структуру папок данной точки

Сценарий Bash ждет процессов и получает код возврата

Я пытаюсь создать скрипт, который запустит много фоновой команды. Для каждой фоновой команды мне нужно получить код возврата.

Я пробовал следующий скрипт:

#!/bin/bash set -x pid=() return=() for i in 1 2 do echo start $i ssh mysql "/root/test$i.sh" & pid[$i]=$! done for i in ${#pid[@]} do echo ${pid[$i]} wait ${pid[$i]} return[$i]=$? if [ ${return[$i]} -ne 0 ] then echo mail error fi done echo ${return[1]} echo ${return[2]} 

Моя проблема во время цикла ожидания, если второй pid заканчивается до первого, я не смогу получить код возврата.

Я знаю, что могу запустить wait pid1 pid2, но с этой командой я не могу получить код возврата всех команд.

Есть идеи ?

Вы можете сделать это, используя временный каталог.

 # Create a temporary directory to store the statuses dir=$(mktemp -d) # Execute the backgrouded code. Create a file that contains the exit status. # The filename is the PID of this group's subshell. for i in 1 2; do { ssh mysql "/root/test$i.sh" ; echo "$?" > "$dir/$BASHPID" ; } & done # Wait for all jobs to complete wait # Get return information for each pid for file in "$dir"/*; do printf 'PID %d returned %d\n' "${file##*/}" "$(<"$file")" done # Remove the temporary directory rm -r "$dir" 

Проблема связана с

 for i in ${#pid[@]} 

Что for i in 2 .

Это должно быть:

 for i in 1 2 

или

 for ((i = 1; i <= ${#pid[@]}; i++)) 

wait "$pid" вернет код выхода задания с помощью bash (и оболочек POSIX, но не zsh ), даже если задание уже было завершено при запуске wait .

Общая реализация без временных файлов.

 #!/usr/bin/env bash ## associative array for job status declare -A JOBS ## run command in the background background() { eval $1 & JOBS[$!]="$1" } ## check exit status of each job ## preserve exit status in ${JOBS} ## returns 1 if any job failed reap() { local cmd local status=0 for pid in ${!JOBS[@]}; do cmd=${JOBS[${pid}]} wait ${pid} ; JOBS[${pid}]=$? if [[ ${JOBS[${pid}]} -ne 0 ]]; then status=${JOBS[${pid}]} echo -e "[${pid}] Exited with status: ${status}\n${cmd}" fi done return ${status} } background 'sleep 1 ; false' background 'sleep 3 ; true' background 'sleep 2 ; exit 5' background 'sleep 5 ; true' reap || echo "Ooops! Some jobs failed" 

Ответ Стефана хороший, но я бы предпочел

 for i in ${!pid[@]} do wait ${pid[i]} return[i]=$? unset "pid[$i]" done 

который будет перебирать ключи массива pid , независимо от того, какие записи все еще существуют, поэтому вы можете адаптировать его, выйти из цикла и повторно запустить весь цикл, и он будет работать. И вам не нужны последовательные значения i для начала.

Конечно, если вы имеете дело с тысячами процессов, то, возможно, подход Степане будет дробно более эффективным, если у вас есть список, не имеющий разреженности.