Executar repetidamente um comando shell até que ele falhe?

191

Eu escrevi um teste confuso que falha de maneira confiável. Eu adicionei algum código de depuração, mas agora quero executar o teste até que ele falhe para que eu possa reunir a saída de depuração.

Eu configurei o teste para que eu possa executá-lo usando:

./runtest

Minha solução atual é escrever um untilfailscript:

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

Então use-o:

untilfail ./runtest

Existe uma solução mais simples?

bradley.ayers
fonte
11
Nota lateral: cite habitualmente "$ @".
Jordanm 19/10

Respostas:

328

while requer um comando para executar, para que você possa usar o mais simples

while ./runtest; do :; done

Isso interromperá o loop quando ./runtestretornar um código de saída diferente de zero (que geralmente é indicativo de falha).

Para simplificar ainda mais a sua solução atual, você deve alterar o script tillfail para ficar assim:

#!/bin/bash

while "$@"; do :; done

E então você pode chamá-lo com qualquer comando que já esteja usando:

untilfail ./runTest --and val1,val2 -o option1 "argument two"
nneonneo
fonte
25
É bom ressaltar também que [é um comando. É um equívoco comum com novos usuários que [faz parte ife whilesintaxe.
Jordanm 19/10
2
Como eu consegui contar quantas vezes funcionou antes de falhar?
GrantJ
13
@ GranJ: é realmente muito simples. Coloque count=0antes do loop e, em vez de :no loop (no-op), coloque (( count++ ))- isso incrementa o contador.
Nneonneo 4/07
14
Um hack produtividade: Se você estiver em um sistema com saye um alto-falante que você pode usar while ./runtest; do :; done && say test failedpara ser notificado se ele nunca pára
Schneems
5
@ Schneems: vale a pena notar que sayé específico para o macOS.
nneonneo
13

Se você não deseja agrupar uma linha de tubulação complexa em um script ou função shell, isso funcionará:

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

A solicitação HTTP nesse caso sempre retorna 200, mas também retorna algum JSON que possui um atributo "HasErrors": true quando há um erro.

Judd Rogers
fonte
1

Tendo tido um problema semelhante em um sistema que teve a lógica de repetição de shell duplicada em todos os lugares, criei uma ferramenta dedicada para resolver isso chamado "repetição":

retry --until=fail ./runtest

Um exemplo mais complexo:

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

Ferramenta disponível em https://github.com/minfrin/retry .

Graham Leggett
fonte