Как выполнить несколько команд параллельно на массиве параметров с помощью bash и завершиться неудачей, если хотя бы одна из них завершилась неудачно - PullRequest
0 голосов
/ 03 января 2019

У меня есть скрипт bash с функцией, которая должна работать параллельно с разными аргументами. Мне нужно знать, если хотя бы одно из выполнений завершилось неудачно (вернул ненулевое значение) - не имеет значения, сколько из них вышло из строя.

Команда принимает массив параметров для выполнения. Мне нужно ограничить одновременность до 4 одновременных запусков из-за высокой нагрузки. Мне также нужно распечатать журналы в родительском процессе (тот, который запускает скрипт bash)

это функция, которую я запускаю:

function run_and_retry {
  EXIT_STATUS=0
  $COMMAND || EXIT_STATUS=$?

  if [ $EXIT_STATUS -ne 0 ]; then
    EXIT_STATUS=0
    $COMMAND || EXIT_STATUS=$?

  fi

  return $EXIT_STATUS
}

Я пытался использовать GNU параллельно и xargs и столкнулся с проблемами в обоих.

С xargs: (не удалось получить статус выхода из него, и он также не работал, когда я запустил его в TravisCI)

PARAMETERS=(first-parameter second-parameter third-parameter)
export -f run_and_retry
echo "${PARAMETERS[@]}" | xargs -P 4 -n 1 -I {} bash -c "run_and_retry {}"

С параллельным GNU:

PARAMETERS=(first-parameter second-parameter third-parameter)
export -f run_and_retry
parallel -j 4 -k --lb 2 run_and_retry {} ::: echo "${PARAMETERS[@]}" 

Ответы [ 2 ]

0 голосов
/ 03 января 2019

Вы , поэтому близки к правильному синтаксису GNU Parallel:

COMMAND=echo
PARAMETERS=(first-parameter second-parameter third-parameter)
parallel -j 4 -k --retries 2 "$COMMAND" {} ::: "${PARAMETERS[@]}" ||
  echo $? commands failed. More than 99 if $? = 100

Или, если вы действительно настаиваете на повторной попытке самостоятельно:

PARAMETERS=(first-parameter second-parameter third-parameter)
export -f run_and_retry
parallel -j 4 -k run_and_retry {} ::: "${PARAMETERS[@]}" ||
  echo One or more commands failed
0 голосов
/ 03 января 2019

Мне нужно знать, если хотя бы одно из выполнений завершилось неудачно (возвращено ненулевое значение)

С posix xargs :

СТАТУС ВЫХОДА

1-125
Не удалось собрать командную строку, соответствующую указанным требованиям, один или несколько вызовов утилиты вернули ненулевой статус завершения или произошла какая-то другая ошибка.

man xargs кажется немного другим:

СТАТУС ВЫХОДА

123, если любой вызов команды завершен со статусом 1-125

Но я бы проверил статус возврата команды и вернул предопределенное число (например, 1) из функции, чтобы обработать это.

parameters=(1 2 3 fail)

func() { 
    COMMAND=sleep
    # I guess OP intends to try running COMMAND twice
    if ! "$COMMAND" 0."$1" && ! "$COMMAND" 0."$1"; then
        return 1
    fi
}

export -f func
if printf "%s\0" "${parameters[@]}" | xargs -0 -P4 -n1 -t -- bash -c 'func $1' -- ; then
   echo "Success!"
else
   echo "Error!"
fi

Живая версия доступна на tutorialspoint .

Ну, мы даже можем посчитать количество детей вручную, и это довольно просто с wait -n. От stackoverflow - ПОДОЖДИТЕ для «1 из многих процессов» до завершения :

bash 4.3 добавил флаг -n к встроенной команде ожидания, которая заставляет сценарий ожидать завершения следующего дочернего процесса.

Так что мы можем просто:

cnt=0
failed=false
for i in "${parameters[@]}"; do
    ( func "$i" ) &
    if (( cnt < 4 )); then
        cnt=$((cnt+1))
    else
        # handle more then 4 processes
        if ! wait -n; then
           failed=true
        fi
    fi
done
# handle still running processes after all have been forked
for i in $(seq $cnt); do
    if ! wait -n; then
        failed=true
    fi
done

if "$failed"; then
    echo "One of the jobs failed!"
fi
...