¿Por qué while [0] entra en bucle infinito?

23

Veo el mismo comportamiento para el ciclo a continuación que el ciclo con while [ 1 ]. ¿Por qué es así?

while [ 0 ]; do
    echo "hello"
done
usuario13107
fuente

Respuestas:

33

Los corchetes individuales en el shell son sinónimo de test(ya sea el comando separado o el shell incorporado), por lo que [ 0 ]significa lo mismo que test 0. testes para hacer comparaciones y probar los atributos de los archivos, como puede leer en su página de manual. Cuando no se le da una expresión que se parezca a una comparación, prueba de archivo o una de las otras operaciones que puede hacer, en su lugar probará si el argumento está presente y es una cadena no vacía. Ninguna 0o 1son entradas realmente apropiadas para la prueba, y como prueba de cadenas no vacías simplemente tiene éxito y su bucle while se repite para siempre.

Quizás quieras probar en su lugar

while false; do
  echo "hello"
done

posiblemente reemplazando falsecon true. O tal vez lo que quieres es usar (( )):

while (( 0 )); do
  echo "hello"
done

Que se comportará como la mayoría de los idiomas, donde 0 significa falla / falso y 1 significa éxito / verdadero.

Submarino alado
fuente
1
Re: "Cuando no se le da una expresión que se parezca a una comparación, prueba de archivo o una de las otras operaciones que puede hacer, simplemente tiene éxito": no creo que sea una buena forma de decirlo. Después de todo, [ ](sin argumento) y [ "" ](con un solo argumento vacío) no tienen éxito.
ruakh
3
Como explica @ruakh, esta afirmación es incorrecta: cuando no se le da una expresión que parezca una comparación, una prueba de archivo o una de las otras operaciones que puede hacer, simplemente tiene éxito. Cualquier argumento único a prueba (ningún argumento único dentro de los corchetes) se considera TRUE si el argumento no es una cadena vacía, y ambos 0y 1no son cadenas vacías. Los nuevos programadores de shell a menudo escriben en if [ 1=2 ]lugar de if [ 1 = 2 ]y se preguntan por qué el primero siempre es cierto. Es cierto porque es un argumento único y no es una cadena vacía.
Ian D. Allen
Buenos puntos, he hecho una corrección.
wingedsubmariner
10

El valor 0 aquí no actúa como una constante numérica, sino como una cadena de caracteres. Estas pruebas son todas equivalentes en su efecto de producir un estado de terminación exitoso:

[ A ]
[ "XYZ" ]
[ 0 ]

estos producen un estado de terminación fallido:

[ ]
[ "" ]

hay un argumento no en blanco, que se evalúa como verdadero lógico. Esto le permite hacer cosas como:

if [ $UNDER_NUCLEAR_ATTACK ] ; then
  launch-missiles -a $DRY_RUN  # $DRY_RUN set to "-n" during testing
fi

La variable UNDER_NUCLEAR_ATTACKse establece en cualquier valor que no esté en blanco para indicar verdadero, o está desarmado o vacío para indicar falso.

Podemos aplicar el !operador para invertir la lógica:

[ ! a ]  # fails: a is nonblank so true; and not true is false.
[ ! ]    # succeeds: blank is false, not blank is true.

Para evaluar una condición numérica, debe usar operadores de prueba numéricos:

 while [ $A -gt $B ] ; do ...

Si Ay Bcontienen cadenas que parecen enteros decimales, se comparan como números, y si Aes mayor que B, el bucle se ejecuta. Supongamos que UNDER_NUCLEAR_ATTACKno es un booleano de tipo cadena que está en blanco o no en blanco, sino que es un booleano numérico que es 0(falso) o algún otro valor (verdadero). En ese caso, escribiríamos la prueba así:

 if [ $UNDER_NUCLEAR_ATTACK -ne 0 ] ; then ...
Kaz
fuente
-1

Una construcción if / then prueba si el estado de salida de una lista de comandos es 0 (ya que 0 significa "éxito" según la convención de UNIX) y, de ser así, ejecuta uno o más comandos.

En resumen, está devolviendo un resultado de prueba de cero.

http://www.tldp.org/LDP/abs/html/testconstructs.html

Stephan
fuente
55
Sí, pero no por la razón que pareces pensar. Si [obtiene solo un argumento (excluyendo el ], por supuesto) sale con el estado cero si el argumento no está vacío, distinto de cero si lo está. Entonces, por ejemplo, [ 1 ]también devolverá un código de salida de 0.
Kevin
-1

El valor 0 se considera verdadero para el ciclo while, por lo tanto, la condición para el ciclo while es verdadero y, por lo tanto, es continuo para mostrar el ciclo infinito. El es verdadero si reemplazamos 0 con 1, ya que cualquier entero que escribamos entre la condición devolverá verdadero

Jyoti Minhas
fuente