Неоднократно запускать команду оболочки, пока не произойдет сбой?

191

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

Я настроил тест, чтобы я мог запустить его с помощью:

./runtest

Мое текущее решение - написать untilfailскрипт:

#!/bin/bash
$@
while [ $? -eq 0 ]; do
    $@
done

Тогда используйте это:

untilfail ./runtest

Есть ли более простое решение?

bradley.ayers
источник
11
Примечание: обычно цитируем "$ @".
Иордания

Ответы:

328

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

while ./runtest; do :; done

Это остановит цикл, когда ./runtestвернет ненулевой код выхода (который обычно указывает на ошибку).

Чтобы еще больше упростить текущее решение, вы должны просто изменить свой сценарий tillfail, чтобы он выглядел следующим образом:

#!/bin/bash

while "$@"; do :; done

И тогда вы можете вызвать его любой командой, которую вы уже используете:

untilfail ./runTest --and val1,val2 -o option1 "argument two"
nneonneo
источник
25
Хорошо также отметить, что [это команда. Это распространенное заблуждение , с новыми пользователями, [является частью ifи whileсинтаксис.
Иордания
2
Как я мог подсчитать, сколько раз он бежал до того, как потерпел неудачу?
GrantJ
13
@GrantJ: это действительно очень просто. Ставить count=0перед циклом, затем вместо :цикла (без операции) ставить (( count++ ))- это увеличивает счетчик.
nneonneo
14
Повышение производительности: если вы работаете в системе с sayгромкоговорителем и можете использовать его, while ./runtest; do :; done && say test failedчтобы получать уведомления о его остановке
Schneems
5
@Schneems: стоит отметить, что это sayзависит от macOS.
nneonneo
13

Если вы не хотите заключать сложную конвейерную линию в скрипт или функцию оболочки, это работает:

while true; do 
  curl -s "https:..." | grep "HasErrors.:true"
  if [[ "$?" -ne 0 ]]; then 
    break
  fi
  sleep 120
done

HTTP-запрос в этом случае всегда возвращает 200, но также возвращает некоторый JSON, который имеет атрибут «HasErrors»: true при возникновении ошибки.

Джадд Роджерс
источник
1

Имея подобную проблему в системе, в которой логика повторения оболочки повторялась повсюду, я создал специальный инструмент для решения этой проблемы, называемый «повтор»:

retry --until=fail ./runtest

Более сложный пример:

retry --until=fail --message="test succeeded" --delay=1 ./runtest

Инструмент доступен по адресу https://github.com/minfrin/retry .

Грэм Леггетт
источник