Como você pode executar um comando no bash até o sucesso

237

Eu tenho um script e quero solicitar ao usuário algumas informações, o script não pode continuar até que o usuário preencha essas informações. A seguir, é minha tentativa de colocar um comando em um loop para conseguir isso, mas não funciona por algum motivo.

echo "Please change password"
while passwd
do
echo "Try again"
done

Eu tentei muitas variações do loop while:

while `passwd`
while [[ "`passwd`" -gt 0 ]]
while [ `passwd` -ne 0 ]]
# ... And much more

Mas não consigo fazê-lo funcionar.

JV
fonte

Respostas:

403
until passwd
do
  echo "Try again"
done

ou

while ! passwd
do
  echo "Try again"
done
Erik
fonte
20
Difícil Ctrl-C com isso.
Dongar
Se você acha que precisará cancelar isso, basta abrir uma nova instância do seu shell (por exemplo, digite "bash") e, quando quiser cancelá-lo, vá para outra janela do terminal e mate o bash recém-gerado processo.
Ethan
50
Fácil de Ctr-C com isso: until passwd; do echo "Try again"; sleep 2; done- tudo o que você precisa fazer é pressionar Ctr-C logo após (dentro de dois segundos) o echotrabalho realizado.
Christian
9
@azmeuk: Tente algo como until passwd || (( count++ >= 5 )); do echo "foo"; done(somente bash, certifique-se de definir a contagem como 0, se existir essa variável) Se você precisar disso para sh simples, aumente o contador no corpo e use []
Justin Sane
2
Depois de se referir a esta página muitas vezes, eu decidi criar uma função festa genérico para repetir comandos, aqui está: gist.github.com/felipou/6fbec22c4e04d3adfae5
felipou
94

Você precisa testar $?, que é o status de saída do comando anterior. passwdsai com 0 se tudo funcionou bem e diferente de zero se a alteração da senha falhar (senha incorreta, incompatibilidade de senha, etc ...)

passwd
while [ $? -ne 0 ]; do
    passwd
done

Com sua versão de backtick, você está comparando a saída do passwd, que seria algo do tipo Enter passworde assim por confirm passworddiante.

Marc B
fonte
2
Não deveria ser $??
Shawn Chin
Eu gosto disso porque é claro como adaptá-lo para a situação oposta. por exemplo, executar um programa com um erro não-determinístico até falhar
Eric
Quando o sucesso é indicado por um código de saída diferente de zero, é isso que você precisa.
Gudlaugur Egilsson 30/01
2
Eu acho que isso pode ser ligeiramente melhorado, alterando o primeiro passwdcom /bin/falsese você tiver algum comando longo e complicado do qual não deseja manter duas versões.
precisa saber é
Deve ser a resposta aceita imho. Isso deve funcionar na maioria das conchas (testadas em bash, mksh e ash) e é facilmente adaptável à situação.
linuxandria 20/04
73

Para elaborar a resposta de @Marc B,

$ passwd
$ while [ $? -ne 0 ]; do !!; done

É uma boa maneira de fazer a mesma coisa que não é específica de comando.

duckworthd
fonte
11
Infelizmente, não funciona para mim (recebo o comando '!!' não encontrado). Como é que isso funciona?
Johannes Rudolph
2
É um truque básico para executar o comando anterior. Por exemplo, se você esquecer de escrever sudona frente de um comando, basta sudo !!executar o comando anterior com privilégios de root.
precisa saber é
1
posso criar um script no meu perfil que possa fazer isso, para que eu possa: $ makelastwork
user230910
2
Como dormir entre as corridas?
Kamil Dziedzic
6

Você pode usar um loop infinito para conseguir isso:

while true
do
  read -p "Enter password" passwd
  case "$passwd" in
    <some good condition> ) break;;
  esac
done
Kurumi
fonte
2
Esta é a única resposta que não exigiu colocar meu comando de várias linhas em uma função. Fiz && breakdepois do meu comando de verificação, em vez do caso de seleção.
Carlin.scott
4

Se alguém que deseja ter um limite de novas tentativas:

max_retry=5
counter=0
until $command
do
   sleep 1
   [[ counter -eq $max_retry ]] && echo "Failed!" && exit 1
   echo "Trying again. Try #$counter"
   ((counter++))
done
aclokay
fonte
1
until $(command)é basicamente sempre errado. Use em until commandvez disso. O $(...)faz com que a saída de commandser ele mesmo executado como um comando e o estado de saída do que de comando secundário para ser o que o loop decide correr ou não diante; é apenas se há é não stdout que o status de saída do comando em si é considerado quando a substituição de comando está presente.
Charles Duffy
$commandtambém não é um ótimo espaço reservado - consulte o BashFAQ # 50 sobre por que o uso de strings para armazenar comandos não é confiável. Ainda assim, isso é melhor do que era; voto negativo retraído.
Charles Duffy
3
while [ -n $(passwd) ]; do
        echo "Try again";
done;
Andrés Rivas
fonte
3
Esta não é a maneira de fazer isso ... você está negando o stdout do psswd e fazendo um teste unário nele. @duckworthd é bom.
Ray Foss
Além disso, porque não há citando, o teste vai portar-se mal quando não está de saída, mas é mais do que uma palavra, ou é uma expressão glob que os arquivos encontrados em diretório atual, ou assim por diante.
Charles Duffy