variable script pasar parametros funciones from entorno else con bash shell scripting boolean sh

script - variables en bash



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

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


TL; DR

bool=true if [ "$bool" = true ]

Problemas con la respuesta de Miku ( original )

No recomiendo la respuesta aceptada 1 . Su sintaxis es bonita pero tiene algunas fallas.

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", var en este ejemplo, se establece explícitamente en verdadera. ¡Todos los otros casos son peligrosamente engañosos!

El último caso (# 5) es especialmente malo 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!

Cotizar sus variables es más seguro, por ejemplo, if "$var"; then if "$var"; then En los casos anteriores, debería recibir una advertencia de que no se encuentra el comando. Pero todavía podemos hacerlo mejor (ver mis recomendaciones en la parte inferior).

También vea la explicación de Mike Holt de 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, por lo que nunca ejecutará la declaración anidada. ¡Sorpresa!

Citando el valor ( "false" ), citando la variable ( "$var" ), o usando test o [[ lugar de [ , no haga una diferencia.

Lo que yo recomiendo:

Aquí hay maneras en que te recomiendo que revises tus "booleanos". Funcionan como se espera.

bool=true if [ "$bool" = true ]; then if [ "$bool" = "true" ]; then if [[ "$bool" = true ]]; then if [[ "$bool" = "true" ]]; then if [[ "$bool" == true ]]; then if [[ "$bool" == "true" ]]; then if test "$bool" = true; then if test "$bool" = "true"; then

Todos ellos son bastante equivalentes. Tendrá que escribir unas cuantas pulsaciones más que los enfoques en las otras respuestas 5, pero su código será más defensivo.

Notas al pie

  1. La respuesta de Miku ya 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 utiliza correctamente o incorrectamente. Por ejemplo, man woman todavía se consideraría un comando válido, incluso si no existe tal página de hombre.
  4. Para comandos inválidos (no existentes), Bash simplemente se quejará de que no se encontró el comando.
  5. Si te importa la longitud, la primera recomendación es la más corta.

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"


Aquí hay una mejora en la respuesta original de miku, que aborda las preocupaciones de Dennis Williamson sobre el caso, donde la variable no está establecida:

the_world_is_flat=true if ${the_world_is_flat:-false} ; then echo "Be careful not to fall off!" fi

Y para probar si la variable es false :

if ! ${the_world_is_flat:-false} ; then echo "Be careful not to fall off!" fi

Sobre otros casos con un contenido desagradable en la variable, este es un problema con cualquier entrada externa que se alimenta a un programa.

Cualquier entrada externa debe ser validada antes de confiar en ella. Pero esa validación debe hacerse solo una vez, cuando se recibe esa entrada.

No tiene que afectar el rendimiento del programa haciéndolo en cada uso de la variable como sugiere Dennis Williamson .


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


En muchos lenguajes de programación, el tipo booleano es, o se implementa como, un subtipo de entero, donde true comporta como 1 y false comporta como 0 :

Mathematically , el álgebra booleana se parece al módulo aritmético de enteros 2. Por lo tanto, si un idioma no proporciona un tipo booleano nativo, la solución más natural y eficiente es usar enteros. Esto funciona con casi cualquier idioma. Por ejemplo, en Bash puedes hacer:

# val=1; ((val)) && echo "true" || echo "false" true # val=0; ((val)) && echo "true" || echo "false" false

hombre bash

((expresión))

La expresión se evalúa de acuerdo con las reglas descritas a continuación en EVALUACIÓN ARITMÉTICA. Si el valor de la expresión es distinto de cero, el estado de retorno es 0; de lo contrario, el estado de retorno es 1. Esto es exactamente equivalente a dejar "expresión".


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.


Larga historia corta:

No hay booleanos en bash

Lo que bash tiene, es 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.

Donde sea que veas true o false en bash, es una cadena o un comando / builtin que solo se usa para su código de salida.

Esta sintaxis ...

if true; then ...

Es esencial...

if COMMAND; then ...

La condición es verdadera siempre que el comando devuelva el código de salida 0.

Podrías hacer esto:

if which foo; then echo "program foo found"; fi

Cuando use corchetes o el comando de test , confíe en el código de salida de esa construcción. Tenga en cuenta que [ ] y [[ ]] también son solo comandos / incorporados como cualquier otro. Asi que ...

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

es solo azúcar sintáctica para ...

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

Por lo tanto, cuando se usa true y false en cualquiera de las construcciones mencionadas, en realidad solo se pasa la cadena "true" o "false" al comando de prueba. Aquí un ejemplo:

Lo creas o no, pero todas esas condiciones están dando el mismo resultado :

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

TL; DR; Siempre comparar contra cadenas o números

Para aclarar esto a los futuros lectores, recomendaría usar siempre comillas alrededor de true y false :

HACER

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

NO HACER

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

Tal vez

if [[ "${var}" != "true" ]]; then ... # creates impression of booleans. Can be used for strict checking of dangerous operations. This condition is false for anything but the literal string "true".


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


Bill Parker está siendo rechazado , porque sus definiciones están anuladas de la convención de código normal. Normalmente, verdadero se define como 0 y falso se define como distinto de cero. 1 trabajará para falso, al igual que 9999 y -1. Lo mismo con los valores de retorno de la función: 0 es éxito y cualquier cosa que no sea cero es falla. Lo siento, aún no tengo la credibilidad de la calle para votar o para responderle directamente.

Bash recomienda usar dobles corchetes ahora como un hábito en lugar de corchetes simples, y el enlace que Mike Holt dio explica las diferencias en cómo funcionan. 7.3. Otros operadores de comparación

Por un lado, -eq es un operador numérico, por lo que tener el código

#**** NOTE *** This gives error message ***** The_world_is_flat=0; if [ "${The_world_is_flat}" -eq true ]; then

emitirá una declaración de error, esperando una expresión entera. Esto se aplica a cualquier parámetro, ya que ninguno es un valor entero. Sin embargo, si colocamos corchetes dobles alrededor de él, no emitirá una declaración de error, pero generará un valor incorrecto (bueno, en el 50% de las posibles permutaciones). Se evaluará a [[0 -eq verdadero]] = éxito, pero también a [[0 -eq falso]] = éxito, lo cual es incorrecto (hmmm ... ¿qué tiene que ver con que el valor incorporado es un valor numérico?).

#**** NOTE *** This gives wrong output ***** The_world_is_flat=true; if [[ "${The_world_is_flat}" -eq true ]]; then

Hay otras permutaciones del condicional que también darán un resultado incorrecto. Básicamente, cualquier cosa (que no sea la condición de error mencionada anteriormente) que establece una variable en un valor numérico y la compara con una construcción verdadera / falsa, o establece una variable en una construcción verdadera / falsa y la compara con un valor numérico. Además, cualquier cosa que establezca una variable en un verdadero / falso incorporado y haga una comparación utilizando -eq . Así que evite -eq para las comparaciones booleanas y evite el uso de valores numéricos para las comparaciones booleanas. Aquí hay un resumen de las permutaciones que darán resultados inválidos:

#With variable set as an integer and evaluating to true/false #*** This will issue error warning and not run: ***** The_world_is_flat=0; if [ "${The_world_is_flat}" -eq true ]; then #With variable set as an integer and evaluating to true/false #*** These statements will not evaluate properly: ***** The_world_is_flat=0; if [ "${The_world_is_flat}" -eq true ]; then # if [[ "${The_world_is_flat}" -eq true ]]; then # if [ "${The_world_is_flat}" = true ]; then # if [[ "${The_world_is_flat}" = true ]]; then # if [ "${The_world_is_flat}" == true ]; then # if [[ "${The_world_is_flat}" == true ]]; then #With variable set as an true/false builtin and evaluating to true/false #*** These statements will not evaluate properly: ***** The_world_is_flat=true; if [[ "${The_world_is_flat}" -eq true ]]; then # if [ "${The_world_is_flat}" = 0 ]; then # if [[ "${The_world_is_flat}" = 0 ]]; then # if [ "${The_world_is_flat}" == 0 ]; then # if [[ "${The_world_is_flat}" == 0 ]]; then

Entonces, ahora a lo que funciona. Use las incorporaciones de verdadero / falso tanto para su comparación como para sus evaluaciones (como señaló Mike Hunt, no las incluya entre comillas). Luego use el signo igual o el signo igual o el doble (= o ==) y los corchetes simples o dobles ([] o [[]]). Personalmente, me gusta el doble signo igual, porque me recuerda las comparaciones lógicas en otros lenguajes de programación y las comillas dobles porque me gusta escribir. Así que estos funcionan:

#With variable set as an integer and evaluating to true/false #*** These statements will work properly: ***** # The_world_is_flat=true/false; if [ "${The_world_is_flat}" = true ]; then # if [[ "${The_world_is_flat}" = true ]]; then # if [ "${The_world_is_flat}" = true ]; then # if [[ "${The_world_is_flat}" == true ]]; then

Ahí tienes.


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.