¿Cómo puedo declarar y utilizar variables booleanas en un script de shell?

Resuelto hassaanm asked hace 14 años • 27 respuestas

Intenté declarar una variable booleana en un script de shell usando la siguiente sintaxis:

variable=$false

variable=$true

¿Es esto correcto? Además, si quisiera actualizar esa variable, ¿usaría la misma sintaxis? Finalmente, ¿es correcta la siguiente sintaxis para usar variables booleanas como expresiones?

if [ $variable ]

if [ !$variable ]
hassaanm avatar Jun 02 '10 04:06 hassaanm
Aceptado

Respuesta revisada (12 de febrero de 2014)

the_world_is_flat=true
# ...do something interesting...
if [ "$the_world_is_flat" = true ] ; then
    echo 'Be careful not to fall off!'
fi

Respuesta original

Advertencias: https://stackoverflow.com/a/21210966/89391

the_world_is_flat=true
# ...do something interesting...
if $the_world_is_flat ; then
    echo 'Be careful not to fall off!'
fi

De: Usar variables booleanas en Bash

La razón por la que la respuesta original se incluye aquí es porque los comentarios anteriores a la revisión del 12 de febrero de 2014 pertenecen únicamente a la respuesta original, y muchos de los comentarios son incorrectos cuando se asocian con la respuesta revisada. Por ejemplo, el comentario de Dennis Williamson sobre bash incorporado trueel 2 de junio de 2010 solo se aplica a la respuesta original, no a la revisada.

miku avatar Jun 01 '2010 21:06 miku

TL;DR

my_bool=true

if [ "$my_bool" = true ]

Problemas con la respuesta de Miku ( original )

No recomiendo la respuesta aceptada 1 . Su sintaxis es bonita, pero tiene algunos defectos.

Digamos que tenemos la siguiente condición.

if $var; then
  echo 'Muahahaha!'
fi

En los siguientes casos 2 , esta condición se evaluará como verdadera y ejecutará el comando anidado.

# Variable var not defined beforehand. Case 1
var=''  # Equivalent to var="".      # Case 2
var=                                 # Case 3
unset var                            # Case 4
var='<some valid command>'           # Case 5

Normalmente, solo desea que su condición se evalúe como verdadera cuando su variable "booleana", varen este ejemplo, esté explícitamente establecida como verdadera. ¡Todos los demás casos son peligrosamente engañosos!

El último caso (#5) es especialmente complicado porque ejecutará el comando contenido en la variable (razón por la cual la condición se evalúa como verdadera para los comandos válidos 3, 4 ).

Aquí hay un ejemplo inofensivo:

var='echo this text will be displayed when the condition is evaluated'
if $var; then
  echo 'Muahahaha!'
fi

# Outputs:
# this text will be displayed when the condition is evaluated
# Muahahaha!

Citar sus variables es más seguro, por ejemplo if "$var"; then. En los casos anteriores, debería recibir una advertencia de que no se encuentra el comando. Pero aún podemos hacerlo mejor (consulte mis recomendaciones al final).

Vea también la explicación de Mike Holt sobre la respuesta original de Miku.

Problemas con la respuesta de Hbar

Este enfoque también tiene un comportamiento inesperado.

var=false
if [ $var ]; then
  echo "This won't print, var is false!"
fi

# Outputs:
# This won't print, var is false!

Es de esperar que la condición anterior se evalúe como falsa y, por lo tanto, nunca se ejecute la declaración anidada. ¡Sorpresa!

Citar el valor ( "false"), citar la variable ( "$var") o usar testo [[en lugar de [, no hace ninguna diferencia.

Lo que recomiendo :

A continuación le recomiendo que compruebe sus "booleanos". Funcionan como se esperaba.

my_bool=true

if [ "$my_bool" = true ]; then
if [ "$my_bool" = "true" ]; then

if [[ "$my_bool" = true ]]; then
if [[ "$my_bool" = "true" ]]; then
if [[ "$my_bool" == true ]]; then
if [[ "$my_bool" == "true" ]]; then

if test "$my_bool" = true; then
if test "$my_bool" = "true"; then

Todos son prácticamente equivalentes. Tendrás que escribir algunas pulsaciones de teclas más que los métodos de las otras respuestas 5 , pero tu código será más defensivo.


Notas a pie de página

  1. Desde entonces, la respuesta de Miku ha sido editada y ya no contiene fallas (conocidas).
  2. No es una lista exhaustiva.
  3. Un comando válido en este contexto significa un comando que existe. No importa si el comando se usa correctamente o incorrectamente. Por ejemplo, man womantodavía se consideraría un comando válido, incluso si no existe dicha página de manual.
  4. Para comandos no válidos (inexistentes), Bash simplemente se quejará de que no se encontró el comando.
  5. Si te importa el largo, la primera recomendación es el más corto.
Dennis avatar Jan 18 '2014 22:01 Dennis

Parece haber algún malentendido aquí sobre el Bash incorporado truey, más específicamente, sobre cómo Bash expande e interpreta las expresiones entre corchetes.

El código en la respuesta de miku no tiene absolutamente nada que ver con el Bash incorporado true, ni /bin/truecon ningún otro tipo del truecomando. En este caso, trueno es más que una simple cadena de caracteres, y nunca se realiza ninguna llamada al truecomando/integrado, ni mediante la asignación de variables ni mediante la evaluación de la expresión condicional.

El siguiente código es funcionalmente idéntico al código de la respuesta de miku:

the_world_is_flat=yeah
if [ "$the_world_is_flat" = yeah ]; then
    echo 'Be careful not to fall off!'
fi

La única diferencia aquí es que los cuatro caracteres que se comparan son 'y', 'e', ​​'a' y 'h' en lugar de 't', 'r', 'u' y 'e'. Eso es todo. No se intenta llamar a un comando o función incorporada llamada yeah, ni hay (en el ejemplo de miku) ningún tipo de manejo especial cuando Bash analiza el token true. Es solo una cadena, y además completamente arbitraria.

Actualización (19 de febrero de 2014): Después de seguir el enlace en la respuesta de miku, ahora veo de dónde viene parte de la confusión. La respuesta de Miku usa corchetes simples, pero el fragmento de código al que vincula no usa corchetes. Es solo:

the_world_is_flat=true
if $the_world_is_flat; then
  echo 'Be careful not to fall off!'
fi

Ambos fragmentos de código se comportarán de la misma manera, pero los corchetes cambian por completo lo que sucede bajo el capó.

Esto es lo que Bash está haciendo en cada caso:

Sin paréntesis:

  1. Expanda la variable $the_world_is_flata la cadena "true".
  2. Intente analizar la cadena "true"como un comando.
  3. Busque y ejecute el truecomando (ya sea integrado o /bin/true, según la versión de Bash).
  4. Compare el código de salida del truecomando (que siempre es 0) con 0. Recuerde que en la mayoría de los shells, un código de salida de 0 indica éxito y cualquier otra cosa indica fracaso.
  5. Dado que el código de salida era 0 (éxito), ejecute la cláusula ifde la declaraciónthen

Soportes:

  1. Expanda la variable $the_world_is_flata la cadena "true".
  2. Analice la expresión condicional ahora completamente expandida, que tiene la forma string1 = string2. El operador es el operador de comparación de cadenas= de bash . Entonces...
  3. Haga una comparación de cadenas en "true"y "true".
  4. Sí, las dos cadenas eran iguales, por lo que el valor del condicional es verdadero.
  5. Ejecute la cláusula ifde la declaración then.

El código sin corchetes funciona porque el truecomando devuelve un código de salida de 0, lo que indica éxito. El código entre corchetes funciona porque el valor de $the_world_is_flates idéntico al literal de cadena trueen el lado derecho del archivo =.

Sólo para aclarar el punto, considere los siguientes dos fragmentos de código:

Este código (si se ejecuta con privilegios de root) reiniciará su computadora:

var=reboot
if $var; then
  echo 'Muahahaha! You are going down!'
fi

Este código simplemente imprime "Buen intento". No se llama al comando de reinicio.

var=reboot
if [ $var ]; then
  echo 'Nice try.'
fi

Actualización (2014-04-14) Para responder la pregunta en los comentarios sobre la diferencia entre =y ==: AFAIK, no hay diferencia. El ==operador es un sinónimo específico de Bash =y, hasta donde he visto, funcionan exactamente igual en todos los contextos.

Sin embargo, tenga en cuenta que me refiero específicamente a los operadores de comparación de cadenas =y ==utilizados en las pruebas [ ]or [[ ]]. No estoy sugiriendo eso =y ==son intercambiables en todas partes en bash.

Por ejemplo, obviamente no puedes hacer una asignación de variables con ==, como var=="foo"(bueno, técnicamente puedes hacer esto, pero el valor de varserá "=foo", porque Bash no ve un ==operador aquí, está viendo un =operador (asignación), seguido de el valor literal ="foo", que simplemente se convierte en "=foo").

Además, aunque =y ==son intercambiables, debes tener en cuenta que el funcionamiento de esas pruebas depende de si las estás usando dentro [ ]de o [[ ]]y también de si los operandos están entrecomillados o no. Puede leer más sobre esto en Guía avanzada de secuencias de comandos Bash: 7.3 Otros operadores de comparación (desplácese hacia abajo hasta la discusión sobre =y ==).

Mike Holt avatar Feb 13 '2014 23:02 Mike Holt

Larga historia corta:

No hay booleanos en Bash

los comandos trueyfalse

Bash tiene expresiones booleanas en términos de comparación y condiciones. Dicho esto, lo que puedes declarar y comparar en Bash son cadenas y números. Eso es todo.

Dondequiera que vea trueo falseen Bash, es una cadena o un comando/integrado que solo se usa para su código de salida.

Esta sintaxis...

if true; then ...

Es esencial...

if COMMAND; then ...

donde esta el comando true. La condición es verdadera siempre que el comando devuelve el código de salida 0. Son funciones integradas de Bash truey false, a veces, también programas independientes que no hacen más que devolver el código de salida correspondiente.


Condiciones enif..then..fi

Cuando utiliza corchetes o el testcomando, confía en el código de salida de esa construcción. Tenga en cuenta que [ ]y [[ ]]también son solo comandos/integrados como cualquier otro. Entonces ...

if [[ 1 == 1 ]]; then echo yes; fi

corresponde a

if COMMAND; then echo yes; fi

y COMMANDaquí está [[con los parámetros1 == 1 ]]

La if..then..ficonstrucción es simplemente azúcar sintáctica. Siempre puedes simplemente ejecutar los comandos separados por un doble símbolo para obtener el mismo efecto:

[[ 1 == 1 ]] && echo yes

Al usar truey falseen estas construcciones de prueba, en realidad solo está pasando la cadena "true"o "false"al comando de prueba. Aquí hay un ejemplo:

Lo creas o no, pero todas esas condiciones producen el mismo resultado :

if [[ false ]]; then ...
if [[ "false" ]]; then ...
if [[ true ]]; then ...
if [[ "true" ]]; then ...

TL;DR; comparar siempre con cadenas o números

Para dejar esto claro a los futuros lectores, recomendaría utilizar siempre comillas alrededor truey false:

HACER

if [[ "${var}" == "true" ]]; then ...
if [[ "${var}" == "false" ]]; then ...
if [[ "${var}" == "yes" ]]; then ...
if [[ "${var}" == "USE_FEATURE_X" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...

NO

# Always use double square brackets in bash!
if [ ... ]; then ...
# This is not as clear or searchable as -n
if [[ "${var}" ]]; then ...
# Creates impression of Booleans
if [[ "${var}" != true ]]; then ...
# `-eq` is for numbers and doesn't read as easy as `==`
if [[ "${var}" -eq "true" ]]; then ...

Tal vez

# Creates impression of Booleans.
# It can be used for strict checking of dangerous operations.
# This condition is false for anything but the literal string "true".
if [[ "${var}" != "true" ]]; then ... 
Hubert Grzeskowiak avatar Nov 03 '2017 09:11 Hubert Grzeskowiak

Utiliza expresiones aritméticas.

#!/bin/bash

false=0
true=1

((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true

Producción:

verdadero
no falso

Quolonel Questions avatar Nov 13 '2014 23:11 Quolonel Questions