¿Cómo puedes ejecutar un comando en bash over hasta el éxito?

237

Tengo un script y quiero pedirle información al usuario, el script no puede continuar hasta que el usuario complete esta información. El siguiente es mi intento de poner un comando en un bucle para lograr esto, pero no funciona por alguna razón.

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

He intentado muchas variaciones del ciclo while:

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

Pero parece que no puedo hacer que funcione.

JV
fuente

Respuestas:

403
until passwd
do
  echo "Try again"
done

o

while ! passwd
do
  echo "Try again"
done
Erik
fuente
20
Difícil de Ctrl-C fuera de esto.
DonGar
Si cree que va a necesitar cancelar esto, simplemente abra una nueva instancia de su shell (por ejemplo, escriba "bash") y, cuando quiera cancelarlo, vaya a otra ventana de terminal y elimine el bash recién generado proceso.
Ethan
50
Fácil de hacer Ctr-C fuera de esto: until passwd; do echo "Try again"; sleep 2; done- todo lo que tiene que hacer es presionar Ctr-C justo después (dentro de los dos segundos dados) echohizo su trabajo.
Christian
99
@azmeuk: intente algo como until passwd || (( count++ >= 5 )); do echo "foo"; done(solo bash, asegúrese de establecer el recuento en 0 si existe esa variable) Si necesita esto para sh simple, incremente el contador en el cuerpo y use []
Justin Sane
2
Después de referirme a esta página muchas veces, decidí crear una función bash genérica para reintentar comandos, aquí está: gist.github.com/felipou/6fbec22c4e04d3adfae5
felipou
94

En su $?lugar, debe probar , que es el estado de salida del comando anterior. passwdsale con 0 si todo funcionó bien, y distinto de cero si el cambio de contraseña falló (contraseña incorrecta, falta de coincidencia de contraseña, etc.)

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

Con su versión de backtick, está comparando la salida de passwd, que sería cosas similares Enter passwordy confirm passwordsimilares.

Marc B
fuente
2
¿No debería ser eso $??
Shawn Chin
Me gusta esto porque está claro cómo adaptarlo para la situación opuesta. por ejemplo, ejecutar un programa con un error no determinista hasta que falle
Eric
Cuando el éxito se indica mediante un código de salida distinto de cero, esto es lo que necesita.
Gudlaugur Egilsson
2
Creo que esto puede mejorarse ligeramente cambiando el primero passwdcon /bin/falsesi tiene algún comando largo y complicado del que no desea conservar dos versiones.
Coladict
Debería ser la respuesta aceptada en mi humilde opinión. Esto debería funcionar en la mayoría de los depósitos (probados en bash, mksh y ash) y se adapta fácilmente a la situación.
linuxandria
73

Para elaborar sobre la respuesta de @Marc B,

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

Es una buena manera de hacer lo mismo que no es un comando específico.

Duckworthd
fuente
11
Desafortunadamente, no funciona para mí (aparece el comando '!!' no encontrado). Como se supone que funciona?
Johannes Rudolph
2
Es un truco bash ejecutar el comando anterior. Por ejemplo, si olvida escribir sudodelante de un comando, simplemente puede sudo !!ejecutar el comando anterior con privilegios de root.
JohnEye
1
¿Puedo hacer un script en mi perfil que pueda hacer esto, así puedo ir: $ makelastwork
user230910
2
¿Cómo dormir entre carreras?
Kamil Dziedzic
6

Puede usar un bucle infinito para lograr esto:

while true
do
  read -p "Enter password" passwd
  case "$passwd" in
    <some good condition> ) break;;
  esac
done
Kurumi
fuente
2
Esta es la única respuesta que no requirió poner mi comando multilínea en una función. Lo hice && breakdespués de mi comando de verificación, en lugar del caso de selección.
carlin.scott
4

Si alguien busca tener límite de reintentos:

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
fuente
1
until $(command)Básicamente siempre está mal. Usar en su until commandlugar. Esto $(...)hace que la salida de commandse ejecute como un comando y que el estado de salida de ese comando secundario sea ​​el que el bucle decide ejecutar o fallar; es sólo si no es ninguna salida estándar que el estado de salida del comando en sí se considera cuando la sustitución de comandos está presente.
Charles Duffy
$commandtampoco es un gran marcador de posición: vea BashFAQ # 50 sobre por qué el uso de cadenas para almacenar comandos no es confiable de manera innata. Aún así, esto es mejor de lo que era; voto negativo retraído.
Charles Duffy
3
while [ -n $(passwd) ]; do
        echo "Try again";
done;
Andrés Rivas
fuente
3
Esta no es la forma de hacerlo ... estás negando el stdout de psswd y luego haciendo una prueba unitaria al respecto. @duckworthd es bueno.
Ray Foss
Por otra parte, porque no hay citando, la prueba se va a portarse mal cuando no es la salida, pero es más de una palabra o expresión es un pegote que coincide con los archivos en el directorio actual, o así sucesivamente.
Charles Duffy