Я смотрю на эффективный способ сделать это.

У меня есть различные команды, которые мне нужно выполнить последовательно; вторая не может работать, если первая не удалась и так далее.

Я прошел через них; но цикл должен проходить через каждую команду, а это не то, что мне нужно делать.

Например, если есть 3 команды: a, b и c; a запускается все время, b запускается только при успешном запуске a, и c должен запускаться только при успешном запуске b, но если b не удалось один раз, он должен начинать все сначала с

LOOP *****************************
until a; do
  echo "a failed, retrying"
  sleep(3)
done
until b; do
  echo "b failed, need to start all over"
  b_failed=1
  break
  START FROM THE BEGIN OF LOOP ***************
done
until c; do
  echo "c failed, need to start all over from a"
  c_failed=1
  break
  START FROM THE BEGIN OF LOOP ***************
done
.... OTHER INSTRUCTIONS
LOOP *****************************

Я попытался использовать обычный цикл, но разрыв выйдет из под цикла, и не начнется с начала. Я хотел бы войти в этот основной цикл, выполнить первую операцию, пока она не пройдет, а затем выполнить вторую; в случае неудачи он запускается с начала цикла, без выполнения всех других команд и так далее. Хотя я, похоже, не могу найти правильный способ сделать это, если я не раздуваю логику с кучей проверок if-else каждой команды.

Есть ли чистый способ сделать это в несколько строк?

РЕДАКТИРОВАТЬ: написал, а не до; сделал исправление

РЕДАКТИРОВАТЬ 2: Большое спасибо за решение! Хотя его нужно изменить, так как я не смог запустить его как есть: в if отсутствует fi для завершения команды и пропущен оператор "then". Я не был в состоянии выполнить do внутри if; так вот что работает для меня:

while true; do
    until a; do
        echo "a failed, retrying"
        sleep(3)
    done
    if [ ! b ]; then
        echo "b failed, need to start all over"
        continue
    else
        c
    fi
    if [ ! c ]; then
        echo "c failed, need to start all over from a"
        continue
    else
        break
    fi
done

1 ответ1

3

Очень простое решение, как отчасти упомянул Squeezy:

until a && b && c; do
    :
done

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

Возвращаемое значение полного выражения && (или цепочки && s) является результатом последнего вычисленного выражения. Поэтому, если какая-либо из этих трех команд потерпит неудачу, последующие команды будут проигнорированы, а команда until увидит false и войдет в его тело, ничего не делать (: это просто no-op для заполнения тела цикла) и цикл вернуться к условию теста a && b && c снова. Если все три удастся, то until пор пока не увидят true и конец.

Так что это хорошо для простого случая, но не хорошо, если вы хотите распечатать эти сообщения о состоянии. Это возможно с || (логическое или) и { } , но это будет очень грязно.

Это лучше, если вы хотите сделать что-то дополнительное при сбое команды, например сообщения о состоянии эха:

while true; do
    until a; do
        echo "a failed, retrying"
        sleep(3)
    done
    if [ ! `b` ]; then
        echo "b failed, need to start all over"
        continue
    fi
    if [ ! `c` ]; then
        echo "c failed, need to start all over from a"
        continue
    fi
    break
done

continue возвращается к началу замкнутого цикла. Помещение числа после его возврата в начало замкнутого цикла на n уровней выше. Хотя в этом нет необходимости, потому что они внутри, if вместо петель. Между прочим, break аналогично будет принимать число и разрывать из n замкнутых циклов.

Секция может также быть , a вместо цикла if [ ! a ]; , если вы предпочитаете, чтобы все выглядело одинаково. Вам нужно добавить until в этом случае.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .