Come puoi eseguire un comando in bash fino al successo


237

Ho uno script e voglio chiedere all'utente alcune informazioni, lo script non può continuare fino a quando l'utente non compila queste informazioni. Quello che segue è il mio tentativo di mettere un comando in un ciclo per raggiungere questo obiettivo, ma non funziona per qualche motivo.

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

Ho provato molte varianti del ciclo while:

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

Ma non riesco a farlo funzionare.

Risposte:


403
until passwd
do
  echo "Try again"
done

o

while ! passwd
do
  echo "Try again"
done

20
Difficile uscire da Ctrl-C.
DonGar,

Se pensi di dover annullare questo, apri una nuova istanza della tua shell (esempio, digita "bash") e, quando vuoi annullarla, vai in un'altra finestra del terminale e uccidi la bash appena generata processi.
Ethan,

50
Facile da usare per Ctr-C: until passwd; do echo "Try again"; sleep 2; done- tutto ciò che devi fare è premere Ctr-C subito dopo (entro due secondi) il echolavoro è stato eseguito.
Christian,

9
@azmeuk: prova qualcosa del genere until passwd || (( count++ >= 5 )); do echo "foo"; done(solo bash, assicurati di impostare il conteggio su 0 se esiste questa variabile) Se ne hai bisogno per sh semplice, incrementa il contatore nel corpo e usa []
Justin Sane il

2
Dopo aver fatto riferimento a questa pagina molte volte, ho deciso di creare una funzione bash generica per riprovare i comandi, eccola: gist.github.com/felipou/6fbec22c4e04d3adfae5
felipou

94

Devi $?invece testare , che è lo stato di uscita del comando precedente. passwdesce con 0 se tutto ha funzionato bene e diverso da zero se la modifica del passwd non è riuscita (password errata, mancata corrispondenza della password, ecc ...)

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

Con la tua versione backtick, stai confrontando l'output di passwd, che sarebbe roba simile Enter passworde confirm passwordsimili.


2
Non dovrebbe essere $??
Shawn Chin,

Mi piace perché è chiaro come adattarlo alla situazione opposta. es. eseguire un programma con un bug non deterministico fino a quando non fallisce
Eric

Quando il successo è indicato da un codice di uscita diverso da zero, questo è ciò di cui hai bisogno.
Gudlaugur Egilsson,

2
Penso che questo possa essere leggermente migliorato cambiando il primo passwdcon /bin/falsese hai qualche comando lungo e complicato di cui non vuoi mantenere due versioni.
Coladict

Dovrebbe essere la risposta accettata imho. Questo dovrebbe funzionare nella maggior parte delle conchiglie (testato in bash, mksh e ash) ed è facilmente adattabile alla situazione.
linuxandria,

73

Per approfondire la risposta di @Marc B,

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

È un bel modo di fare la stessa cosa che non è specifico del comando.


11
Sfortunatamente non funziona per me (ricevo il comando '!!' non trovato). Come dovrebbe funzionare?
Johannes Rudolph,

2
È un trucco bash per eseguire il comando precedente. Ad esempio, se dimentichi di scrivere sudodavanti a un comando, puoi semplicemente sudo !!eseguire il comando precedente con i privilegi di root.
JohnEye,

1
posso creare uno script nel mio profilo che può farlo, così posso andare: $ makelastwork
user230910

2
Come dormire tra le piste?
Kamil Dziedzic,

6

È possibile utilizzare un ciclo infinito per raggiungere questo obiettivo:

while true
do
  read -p "Enter password" passwd
  case "$passwd" in
    <some good condition> ) break;;
  esac
done

2
Questa è l'unica risposta che non ha richiesto l'inserimento del mio comando multilinea in una funzione. L'ho fatto && breakdopo il mio comando di verifica, invece del caso selezionato.
carlin.scott,

4

Se qualcuno che desidera avere un limite di tentativi:

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

1
until $(command)è fondamentalmente sempre sbagliato. Usa until commandinvece. L' $(...)provoca l' uscita di commandessere sé eseguito come un comando, e lo stato di uscita di quel comando secondaria per essere ciò che l'anello decide di eseguire o fallire su; è solo se non v'è alcuna stdout che lo stato di uscita del comando stesso è considerato quando la sostituzione di comando è presente.
Charles Duffy,

$commandnon è nemmeno un ottimo segnaposto - vedi BashFAQ # 50 sul perché l'uso delle stringhe per memorizzare i comandi è innato inaffidabile. Tuttavia, questo è meglio di prima; downvote ritirato.
Charles Duffy,

3
while [ -n $(passwd) ]; do
        echo "Try again";
done;

3
Questo non è il modo di farlo ... stai negando lo stdout di psswd e poi stai facendo un test unario su di esso. @duckworthd è buono.
Ray Foss,

Inoltre, perché non c'è citando, il test sta andando a comportarsi male quando non è uscita, ma è più di una parola, o è un'espressione globale che i file partite nella directory corrente, o così via.
Charles Duffy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.