bash - pasar - variables en shell script




¿Cómo declarar y usar variables booleanas en shell script? (11)

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

variable=$false

variable=$true

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

if [ $variable ]

if [ !$variable ]

¿Cómo declarar y usar variables booleanas en shell script?

A diferencia de muchos otros lenguajes de programación, Bash no separa sus variables por "tipo". [1]

Así que la respuesta es bastante clara. No hay una boolean variable en bash. Sin embargo :

Usando una declaración de declaración, podemos limitar la asignación de valores a las variables. [2]

#!/bin/bash
declare -ir BOOL=(0 1) #remember BOOL can't be unset till this shell terminate
readonly false=${BOOL[0]}
readonly true=${BOOL[1]}
#same as declare -ir false=0 true=1
((true)) && echo "True"
((false)) && echo "False"
((!true)) && echo "Not True"
((!false)) && echo "Not false"

La opción r en declare y readonly se usa para indicar explícitamente que las variables son solo de lectura . Espero que el propósito sea claro.


POSIX (interfaz del sistema operativo portátil)

Extraño aquí el punto clave, que es la portabilidad. Es por eso que mi cabecera tiene POSIX en sí mismo.

Esencialmente, todas las respuestas votadas son correctas, con la excepción de que son demasiado específicas para BASH .

Básicamente, solo deseo agregar más información acerca de la portabilidad.

  1. [ y ] corchetes como en [ "$var" = true ] no son necesarios, y puede omitirlos y usar el comando de test directamente:

    test "$var" = true && CodeIfTrue || CodeIfFalse
    
  2. Imagina lo que esas palabras true y false significan para la concha, pruébalo tú mismo:

    echo $((true))
    
    0
    
    echo $((false))
    
    1
    

    Pero usando comillas:

    echo $(("true"))
    
    bash: "true": syntax error: operand expected (error token is ""true"")
    sh (dash): sh: 1: arithmetic expression: expecting primary: ""true""
    

    Lo mismo va para:

    echo $(("false"))
    

    El shell no puede interpretarlo más que una cadena. Espero que tengas la idea de lo bueno que es usar palabras clave adecuadas sin comillas.

    Pero nadie lo dijo en respuestas anteriores.

  3. ¿Lo que esto significa? Bueno, varias cosas.

    • Debería acostumbrarse a que las palabras clave booleanas en realidad se traten como números, que es true = 0 y false = 1 , recuerde que todos los valores distintos de cero se tratan como false .

    • Como se tratan como números, también debe tratarlos así, es decir, si define la variable, diga:

      var_a=true
      echo "$var_a"
      
       true
      

      Puedes crear un valor opuesto de ella con:

      var_a=$((1 - $var_a))
      echo "$var_a"
      
      1
      

      Como puede ver por sí mismo, el shell imprime la cadena true la primera vez que la usa, pero desde entonces, todo funciona a través del número 0 o 1 , respectivamente.

Finalmente, lo que debes hacer con toda esa información.

  • El primer buen hábito sería asignar 0 lugar de true ; 1 lugar de false .

  • El segundo buen hábito sería probar si la variable es / no es igual a cero:

    test "$var" -eq 0 && CodeIfTrue || CodeIfFalse
    

Aquí hay un ejemplo simple que funciona para mí:

temp1=true
temp2=false

if [ "$temp1" = true ] || [ "$temp2" = true ]
then
    echo "Do something." 
else
    echo "Do something else."
fi

Aquí hay una implementación de una mano corta if true .

# Function to test if a variable is set to "true"
_if () {
    [ "${1}" == "true" ] && return 0
    [ "${1}" == "True" ] && return 0
    [ "${1}" == "Yes" ] && return 0
    return 1
}

Ejemplo 1

my_boolean=true

_if ${my_boolean} && {
    echo "True Is True"
} || {
    echo "False Is False"
}

Ejemplo 2

my_boolean=false
! _if ${my_boolean} && echo "Not True is True"

Bash realmente confunde el problema con los gustos de [ , [[ , (( , $(( , etc.)

Todo el tratamiento en los espacios de código de cada uno. Supongo que esto es sobre todo histórico, donde Bash tuvo que fingir ser sh vez en cuando.

La mayoría de las veces, solo puedo elegir un método y seguirlo. En este caso, tiendo a declarar (preferiblemente en un archivo de biblioteca común que puedo incluir con . En mi (s) script (s) real (es)).

TRUE=1; FALSE=0

Entonces puedo usar el operador aritmético (( ... )) para probar así.

testvar=$FALSE

if [[ -d ${does_directory_exist} ]]
then
    testvar=$TRUE;
fi

if (( testvar == TRUE )); then
    # do stuff because the directory does exist
fi
  1. Tienes que ser disciplinado. Su testvar debe estar configurado en $TRUE o $FALSE en todo momento.

  2. En los comparadores (( ... )) , no necesita los $ precedentes, lo que lo hace más legible.

  3. Puedo usar (( ... )) porque $TRUE=1 y $FALSE=0 , es decir, valores numéricos.

  4. La desventaja es tener que usar $ ocasionalmente:

    testvar=$TRUE
    

    que no es tan bonito.

No es una solución perfecta, pero cubre todos los casos, necesito una prueba de este tipo.


En lugar de simular un booleano y dejar una trampa para futuros lectores, ¿por qué no usar un mejor valor que el verdadero y el falso?

Por ejemplo:

build_state=success
if something-horrible; then
  build_state=failed
fi

if [[ "$build_state" == success ]]; then
  echo go home, you are done
else
  echo your head is on fire, run around in circles
fi

Encontré confusas las respuestas existentes.

Personalmente, solo quiero tener algo que se vea y funcione como C.

Este fragmento funciona muchas veces al día en producción:

snapshotEvents=true

if ($snapshotEvents)
then
    # do stuff if true
fi

Y para mantener a todos contentos, probé:

snapshotEvents=false

if !($snapshotEvents)
then
    # do stuff if false
fi

Que también funcionó bien.

$snapshotEvents evalúa el contenido del valor de la variable. Así que necesitas el $ .

Realmente no necesitas los paréntesis, los encuentro útiles.


Hace mucho tiempo, cuando todo lo que teníamos era sh , los booleanos se manejaban confiando en una convención del programa de test donde la test devuelve un estado de salida falso si se ejecuta sin argumentos. Esto permite que uno piense en una variable que se anula como falsa y que la variable tiene un valor como verdadero. Hoy en día, la prueba está incorporada a bash y es comúnmente conocida por su alias de un carácter [ (o un ejecutable para usar en shells que carecen de él, como notas del dolmen):

FLAG="up or <set>"

if [ "$FLAG" ] ; then 
    echo 'Is true'
else 
    echo 'Is false'
fi

# unset FLAG
#    also works
FLAG=

if [ "$FLAG" ] ; then
    echo 'Continues true'
else
    echo 'Turned false'
fi

Debido a las convenciones de citación, los escritores de guiones prefieren usar el comando compuesto [[ que imita la test pero tiene una sintaxis más agradable: no es necesario citar las variables con espacios, se puede usar && y || como operadores lógicos con extraña prioridad, y no hay limitaciones POSIX en el número de términos.

Por ejemplo, para determinar si FLAG está configurado y COUNT es un número mayor que 1:

FLAG="u p"
COUNT=3

if [[ $FLAG  && $COUNT -gt '1' ]] ; then 
    echo 'Flag up, count bigger than 1'
else 
    echo 'Nope'
fi

Esto puede resultar confuso cuando se necesitan espacios, cadenas de longitud cero y variables nulas, y también cuando el script necesita trabajar con varios shells.


Parece que hay algunos malentendidos aquí acerca de Bash builtin true , y más específicamente, acerca de cómo Bash se expande e interpreta expresiones entre paréntesis.

El código en la respuesta de miku no tiene absolutamente nada que ver con la función Bash incorporada true , ni con /bin/true , ni con ningún otro sabor del comando true . En este caso, true no es más que una simple cadena de caracteres, y nunca se realiza una llamada al comando / builtin true , ni por la asignación de variables, ni por la evaluación de la expresión condicional.

El siguiente código es funcionalmente idéntico al código en 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. No se ha intentado llamar a un comando o una función incorporada llamada yeah , ni hay (en el ejemplo de miku) ningún tipo de manejo especial que se esté produciendo cuando Bash analiza el token true . Es solo una cuerda, y completamente arbitraria en eso.

Actualización (2014-02-19): 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 utiliza corchetes simples, pero el fragmento de código al que se 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 paréntesis cambian por completo lo que está pasando debajo del capó.

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

No hay corchetes:

  1. Expanda la variable $the_world_is_flat a la cadena "true" .
  2. Intente analizar la cadena "true" como un comando.
  3. Busque y ejecute el comando true (ya sea incorporado o /bin/true , dependiendo de la versión de Bash).
  4. Compare el código de salida del comando true (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 falla.
  5. Como el código de salida fue 0 (correcto), ejecute la cláusula if de then

Soportes:

  1. Expanda la variable $the_world_is_flat a la cadena "true" .
  2. Analice la expresión condicional ahora totalmente expandida, que tiene el formato string1 = string2 . El operador = es el operador de comparación de cadenas de bash. Asi que...
  3. Haz 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 if de then .

El código sin corchetes funciona, porque el comando true devuelve un código de salida de 0, que indica el éxito. El código entre corchetes funciona, porque el valor de $the_world_is_flat es idéntico a la cadena literal en el lado derecho de = .

Solo para llevar el punto a casa, 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". El comando de reinicio no se llama.

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

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

Sin embargo, tenga en cuenta que estoy hablando específicamente de los operadores de comparación de cadenas = y == utilizados en las pruebas [ ] o [[ ]] . No estoy sugiriendo que = y == sean intercambiables en todas partes en bash.

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

Además, aunque = y == son intercambiables, debe tener en cuenta que la forma en que funcionan las pruebas depende de si lo está utilizando dentro de [ ] o [[ ]] , y también de si los operandos se citan o no. Puede leer más sobre eso en la Guía avanzada de scripts de Bash: 7.3 Otros operadores de comparación (desplácese hacia abajo hasta la discusión de = y == ).


Usa expresiones aritméticas.

#!/bin/bash

false=0
true=1

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

Salida:

cierto
No falso


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://.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

Desde: Usando variables booleanas en Bash

La razón por la que se incluye aquí la respuesta original es porque los comentarios anteriores a la revisión del 12 de febrero de 2014 corresponden ú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 builtin true el 2 de junio de 2010 solo se aplica a la respuesta original, no a la revisada.







sh