Traté de 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 correcta la siguiente sintaxis para usar variables booleanas como expresiones?
if [ $variable ]
if [ !$variable ]
true
yfalse
en el contexto de la mayoría de los fragmentos a continuación, son solo cadenas simples, no elbash built-ins
!!! Lea la respuesta de Mike Holt a continuación. (Este es un ejemplo en el que una respuesta muy votada y aceptada es confusa en mi humilde opinión y oculta el contenido perspicaz en respuestas menos votadas)true
. Resulta que la respuesta original de Miku realmente llamó altrue
incorporado, pero la respuesta revisada no. Esto provocó que dichos comentarios parecieran estar equivocados sobre cómo funcionaba el código de Miku. La respuesta de Miku ha sido editada para mostrar explícitamente tanto el código original como el revisado. Esperemos que esto alivie la confusión de una vez por todas.[ true ] && echo yes, true is true
y (upppsss)[ false ] && echo yes, false is also true
. / bin / true y / bin / false da un código de retorno $? para funciones no para comparación.variable=something
de lo que es cierto, si no se establece,variable=
eso sería falso[[ $variable ]] && echo true || echo false
e inverso[[ ! $variable ]] && echo false || echo true
Respuestas:
Respuesta revisada (12 de febrero de 2014)
Respuesta original
Advertencias: https://stackoverflow.com/a/21210966/89391
De: Uso de variables booleanas en Bash
La razón por la cual la respuesta original se incluye aquí es porque los comentarios antes de la revisión del 12 de febrero de 2014 se refieren solo 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.fuente
if
instrucción está ejecutando el contenido de la variable que es el Bash incorporadotrue
. Cualquier comando podría establecerse como el valor de la variable y se evaluaría su valor de salida.&&
y||
:# t1=true; t2=true; f1=false;
#if $t1 || $f1; then echo is_true ; else echo is_false; fi;
(devuelve "true", ya que t1 = true) #if $t1 && $f1 || $t2; then echo is_true ; else echo is_false; fi
(devuelve "true", ya que t2 = true) . Nuevamente, esto SOLO funciona porque "verdadero" / "falso" son bash-builtins (devolviendo verdadero / falso). No puede usar "if $ var ..." a menos que var sea un cmd (es decir, verdadero o falso)TL; DR
Problemas con la respuesta ( original ) de Miku
Yo no recomiendo la respuesta aceptada 1 . Su sintaxis es bonita, pero tiene algunos defectos.
Digamos que tenemos la siguiente condición.
En los siguientes casos 2 , esta condición se evaluará como verdadera y ejecutará el comando anidado.
Por lo general, 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 demás casos son peligrosamente engañosos!El último caso (# 5) es especialmente travieso 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:
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 (vea mis recomendaciones al final).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.
Es de esperar que la condición anterior se evalúe como falsa, por lo que nunca se ejecutará la instrucción anidada. ¡Sorpresa!
Citando el valor (
"false"
), citando la variable ("$var"
), o usandotest
o en[[
lugar de[
, no hace la diferencia.Lo que hago recomiendo:
Aquí hay formas en que le recomiendo que revise sus "booleanos". Funcionan como se esperaba.
Todos son más o menos equivalentes. Tendrá que escribir algunas teclas más que los enfoques en las otras respuestas 5 , pero su código será más defensivo.
Notas al pie
man woman
, aún se consideraría un comando válido, incluso si no existe tal página de manual.fuente
==
con[
otest
no es portátil. Teniendo en cuenta la portabilidad es la única ventaja[
/test
tiene más[[
, quédese con=
.Parece que hay algunos malentendidos aquí sobre el Bash incorporado
true
, y más específicamente, sobre cómo Bash expande e interpreta las expresiones entre paréntesis.El código en la respuesta de miku no tiene absolutamente nada que ver con el Bash incorporado
true
, ni/bin/true
, ni ningún otro sabor deltrue
comando. En este caso,true
no es más que una simple cadena de caracteres, y nunca se realiza ninguna llamada altrue
comando / incorporado, 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:
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 nombre incorporado
yeah
, ni hay (en el ejemplo de miku) ningún tipo de manejo especial cuando Bash analiza el tokentrue
. Es solo una cadena, y completamente arbitraria.Actualización (19/02/2014): después de seguir el enlace en la respuesta de miku, ahora veo de dónde proviene parte de la confusión. La respuesta de Miku usa corchetes simples, pero el fragmento de código al que enlaza no usa corchetes. Es solo:
Ambos fragmentos de código se comportarán la misma manera, pero los corchetes cambian por completo lo que sucede debajo del capó.
Esto es lo que Bash está haciendo en cada caso:
Sin corchetes:
$the_world_is_flat
a la cadena"true"
."true"
como un comando.true
comando (ya sea un incorporado o/bin/true
, dependiendo de la versión de Bash).true
comando (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.if
declaraciónthen
Soportes:
$the_world_is_flat
a la cadena"true"
.string1 = string2
. El=
operador es la comparación de cadenas de bash operador de . Entonces..."true"
y"true"
.if
declaraciónthen
.El código sin corchetes funciona, porque el
true
comando devuelve un código de salida de 0, que indica éxito. El código entre corchetes funciona, porque el valor de$the_world_is_flat
es idéntico al literal de cadenatrue
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:
Este código simplemente imprime "Buen intento". El comando de reinicio no se llama.
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=
, por lo que he visto, funcionan exactamente igual en todos los contextos.Nótese, sin embargo, que estoy hablando específicamente acerca de las
=
y==
los operadores de comparación de cadena utilizadas por cualquiera[ ]
o[[ ]]
pruebas. No estoy sugiriendo eso=
y==
son intercambiables en todas partes en bash.Por ejemplo, obviamente no puede hacer una asignación variable con
==
, comovar=="foo"
(bueno, técnicamente puede hacer esto, pero el valor devar
será"=foo"
, porque Bash no está viendo un==
operador aquí, está viendo un=
operador (asignación), seguido de el valor literal="foo"
, que simplemente se convierte"=foo"
).También, aunque
=
y==
son intercambiables, usted debe tener en cuenta que la forma en esas pruebas de trabajo no depende de si se está usando en el interior[ ]
o[[ ]]
, y también de si o no los operandos se citan. Puede leer más sobre eso en la Guía avanzada de secuencias de comandos Bash: 7.3 Otros operadores de comparación (desplácese hacia abajo hasta la discusión de=
y==
).fuente
$the_world_is_flat && echo "you are in flatland!"
true
se hicieron con respecto a la respuesta original. (La respuesta revisada el 12 de febrero de 2014 no fue presentada por miku.) He editado la respuesta para incluir tanto original como revisado. Entonces los comentarios de las personas tienen sentido.true
. ¿Hay alguna manera? Sospecho que muchos programadores que están acostumbrados a idiomas más estrictos que ven esta respuesta para ayudarlos a mezclar un poco debash
pegamento para facilitarles un poco la vida querrían un===
operador para que las cadenas y los "booleanos" no sean realmente intercambiables. En caso de que sólo se adhieren a 0 y 1 y su uso(( $maybeIAmTrue ))
como se sugiere en Quolonel pregunta 's respuesta ?true
, pero generalmente no como algo para comparar una variable, ya que lo realtrue
no tiene valor per se. Todo lo que hace es establecer el estado de salida en0
, lo que indica éxito. Vale la pena señalar que es esencialmente equivalente al llamado "comando nulo", o:
. En cuanto a usar0
y1
, eso es lo que hago en todos mis scripts en estos días donde necesito booleanos. Y uso el(( ))
operador en lugar de[[ ]]
evaluar. Entonces, por ejemplo, si tengoflag=0
, entonces puedo hacerloif (( flag )); then ...
Usa expresiones aritméticas.
Salida:
fuente
!
, o se expandirá el historial.((! foo))
funciona, también lo hace! ((foo))
. Me encanta esta solución, por cierto. Finalmente una forma concisa de hacer variables booleanas.((foo || bar))
Funciona como se esperaba.(())
expande las variables de forma recursiva, lo que no esperaba.foo=bar; bar=baz; ((foo)) && echo echo
no imprime nada, pero es cierto conbaz=1
. Para que pueda apoyarfoo=true
yfoo=false
también 0 o 1 haciendotrue=1
.Larga historia corta:
No hay booleanos en Bash
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.
Donde sea que vea
true
ofalse
en Bash, es una cadena o un comando / incorporado que solo se usa para su código de salida.Esta sintaxis ...
Es esencial...
La condición es verdadera siempre que el comando devuelve el código de salida 0.
true
yfalse
son Bash incorporados y, a veces, también programas independientes que no hacen nada más que devolver el código de salida correspondiente.El condicional anterior es equivalente a:
Cuando utiliza corchetes o el
test
comando, confía en el código de salida de esa construcción. Tenga en cuenta que[ ]
y[[ ]]
también son solo comandos / incorporados como cualquier otro. Entonces ...corresponde a
y el
COMMAND
aquí es[[ 1 == 1 ]]
La
if..then..fi
construcción es solo azúcar sintáctica. Siempre puede ejecutar los comandos separados por un doble ampersand para el mismo efecto:Al usar
true
yfalse
en 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 esas condiciones están dando el mismo resultado :
TL; DR; siempre compara con cadenas o números
Para dejar esto en claro a los futuros lectores, recomendaría siempre usar comillas
true
yfalse
:HACER
No
Tal vez
fuente
T
yF
dejar en claro que esos no son valores booleanos reales.[
(es decirtest
)[[
y usar el que sea adecuado para su necesidad.if ....; then mytest='-gt'; else mytest='-eq'; fi; #several lines of code; if [ "$var1" "$mytest" "$var2" ]; then ...; fi
Hace mucho tiempo, cuando todo lo que teníamos era
sh
, los booleanos se manejaban confiando en una convención deltest
programa donde setest
devuelve un estado de salida falso si se ejecuta sin ningún argumento.Esto le permite a uno pensar en una variable que no está configurada como falsa y que la variable está configurada en cualquier valor como verdadero. Hoy en día,
test
está integrado en Bash y es conocido comúnmente por su alias de un solo carácter[
(o un ejecutable para usar en proyectiles que no lo tienen, como señala dolmen):Debido a las convenciones de citas, los escritores de guiones prefieren usar el comando compuesto
[[
que imitatest
, pero tiene una sintaxis más agradable: las variables con espacios no necesitan ser citadas; uno puede usar&&
y||
como operadores lógicos con precedencia extraña, 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:
Esto puede ser confuso cuando se necesitan espacios, cadenas de longitud cero y variables nulas y también cuando su script necesita trabajar con varios shells.
fuente
[
no es solo un alias por dentrobash
. Este alias también existe como un archivo binario (o como un enlace que apunta a) y se puede usar con el baresh
. Compruebels -l /usr/bin/\[
. Conbash
/zsh
deberías usarlo,[[
es un verdadero interno puro y mucho más poderoso.[
ytest
también es un Bash SHELL BUILTIN COMMAND de acuerdo con la página del manual de Bash, por lo que no debería haber un problema en el rendimiento. Lo mismo con, por ejemplo, Dash. (/ bin / sh puede ser solo un enlace simbólico a / bin / dash). Para usar el ejecutable tienes que usar la ruta completa, es decir/usr/bin/\[
.A diferencia de muchos otros lenguajes de programación, Bash no segrega sus variables por "tipo". [1]
Entonces la respuesta es bastante clara. No hay ninguna variable booleana en Bash.
Sin embargo:
Usando una declaración de declaración, podemos limitar la asignación de valor a las variables. [2]
La
r
opción endeclare
yreadonly
se usa para indicar explícitamente que las variables son de solo lectura . Espero que el propósito sea claro.fuente
declare -ir false=0 true=1
? ¿Cuál es la ventaja de usar una matriz?r
opción y elreadonly
comando. Lo haría de la manera que sugirió en mis scriptsdeclare and use boolean variables
Podríamos, en más de una forma, imitar / asumir que una variable tiene un tipo . No vi eso mencionado en ninguna parte de su respuesta.En lugar de fingir un booleano y dejar una trampa para futuros lectores, ¿por qué no usar un valor mejor que verdadero y falso?
Por ejemplo:
fuente
0
obliga afalse
y1
haciatrue
. En lo que respecta a los códigos de salida del programa (que bash usa históricamente) es0
para un resultado positivo otrue
y todo lo demás es negativo / error ofalse
.POSIX (interfaz del sistema operativo portátil)
Echo de menos el punto clave, que es la portabilidad. Es por eso que mi encabezado tiene POSIX en sí mismo.
Esencialmente, todas las respuestas votadas son correctas, con la excepción de que son demasiado específicas de Bash .
Básicamente, solo deseo agregar más información sobre portabilidad.
[
y los]
corchetes como en[ "$var" = true ]
no son necesarios, y puede omitirlos y usar eltest
comando directamente:Nota importante: ya no recomiendo esto, ya que se está desaprobando lentamente y es más difícil combinar varias declaraciones.
Imagínese lo que esas palabras
true
yfalse
decir a la cáscara, prueba usted mismo:Pero usando comillas:
Lo mismo va para:
El shell no puede interpretarlo más que una cadena. Espero que te hagas una idea de lo bueno que es usar palabras clave adecuadas sin comillas .
Pero nadie lo dijo en respuestas anteriores.
¿Qué significa esto? Bueno, varias cosas.
Debería acostumbrarse a que las palabras clave booleanas se traten como números, es decir
true
=0
yfalse
=1
, recuerde que todos los valores distintos de cero se tratan comofalse
.Como se tratan como números, también debe tratarlos así, es decir, si define una variable, diga:
puedes crear un valor opuesto con:
Como puede ver por sí mismo, el shell imprime la
true
cadena por primera vez que lo usa, pero desde entonces, todo funciona a través de un número que0
representatrue
o1
representafalse
, respectivamente.Finalmente, qué debes hacer con toda esa información
Primero, un buen hábito sería asignar en
0
lugar detrue
;1
en lugar defalse
.El segundo buen hábito sería probar si la variable es / no es igual a cero:
fuente
Con respecto a la sintaxis, esta es una metodología simple que uso (por ejemplo) para administrar lógica booleana de manera consistente y sensata:
Si la variable nunca se declara, la respuesta es:
# false
Entonces, una forma simple de establecer una variable en verdadero (usando esta metodología de sintaxis) sería
var=1
; por el contrario,var=''
.Referencia:
-n
= Verdadero si la longitud de la cadena var no es cero.-z
= Verdadero si la longitud de la cadena var es cero.fuente
En muchos lenguajes de programación, el tipo booleano es, o se implementa como, un subtipo de entero, donde se
true
comporta como1
y sefalse
comporta como0
:Booleano en do
Booleano en Python
Booleano en Java
Matemáticamente , el álgebra booleana se parece al módulo aritmético de enteros 2. Por lo tanto, si un idioma no proporciona el 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:
hombre bash :
fuente
Bill Parker está siendo rechazado , porque sus definiciones se invierten de la convención de código normal. Normalmente, verdadero se define como 0 y falso se define como distinto de cero. 1 funcionará para falso, al igual que 9999 y -1. Lo mismo con los valores de retorno de la función: 0 es correcto y cualquier cosa que no sea cero es un error. Lo siento, todavía no tengo la credibilidad de la calle para votar o responderle directamente.
Bash recomienda usar corchetes dobles ahora como un hábito en lugar de corchetes individuales, y el enlace que Mike Holt le 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ódigoemitirá una declaración de error, esperando una expresión entera. Esto se aplica a cualquiera de los parámetros, ya que ninguno es un valor entero. Sin embargo, si ponemos dos corchetes a su alrededor, no emitirá una declaración de error, pero arrojará 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é hay de que ese valor incorporado sea un valor numérico?).
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 un valor verdadero / falso, o establece una variable con un valor verdadero / falso y la compara con un valor numérico. Además, cualquier cosa que establezca una variable en verdadero / falso incorporado y haga una comparación usando
-eq
. Por lo tanto, evite-eq
las comparaciones booleanas y evite usar valores numéricos para las comparaciones booleanas. Aquí hay un resumen de las permutaciones que darán resultados no válidos:Entonces, ahora a lo que funciona. Use los componentes verdaderos / falsos tanto para su comparación como para sus evaluaciones (como señaló Mike Hunt, no las incluya entre comillas). Luego use un signo igual o simple o doble (= o ==) y corchetes simples o dobles ([] o [[]]). Personalmente, me gusta el signo de doble igual, porque me recuerda las comparaciones lógicas en otros lenguajes de programación y las comillas dobles solo porque me gusta escribir. Entonces estos funcionan:
Ahí tienes.
fuente
true
/false
incorporados no se usan aquí (ignore lo que podría implicar el resaltado de sintaxis de algunos editores), especialmente en los[…]
casos en que puede considerarlo aquí como una cadena simple (una que se proporciona como parámetro del[
comando).Mis hallazgos y sugerencias difieren un poco de las otras publicaciones. Descubrí que podía usar "booleanos" básicamente como lo haría en cualquier lenguaje "normal", sin el "salto de aro" sugerido ...
No hay necesidad de
[]
comparaciones explícitas de cadenas ... Intenté múltiples distribuciones de Linux. Probé Bash, Dash y BusyBox . Los resultados fueron siempre los mismos. No estoy seguro de qué están hablando las publicaciones originales más votadas. ¿Quizás los tiempos han cambiado y eso es todo?Si establece una variable en
true
, posteriormente se evalúa como "afirmativa" dentro de un condicional. Póngalo enfalse
, y se evalúa como "negativo". Muy sencillo! ¡La única advertencia es que una variable indefinida también se evalúa como verdadera ! Sería bueno si hiciera lo contrario (como lo haría en la mayoría de los idiomas), pero ese es el truco: solo necesita inicializar explícitamente sus booleanos en verdadero o falso .¿Por qué funciona de esta manera? Esa respuesta es doble. A) verdadero / falso en un shell realmente significa "sin error" frente a "error" (es decir, 0 frente a cualquier otra cosa). B) verdadero / falso no son valores, sino más bien declaraciones en scripts de shell. Con respecto al segundo punto, ejecutar
true
ofalse
en una línea por sí mismo establece el valor de retorno para el bloque en el que se encuentra ese valor,false
es decir, es una declaración de "error encontrado", donde el verdadero "borra" eso. Usarlo con una asignación a una variable "devuelve" eso a la variable. Una variable indefinida se evalúa comotrue
en un condicional porque representa igualmente 0 o "no se encontró ningún error".Vea el ejemplo de líneas bash y resultados a continuación. Pruébelo usted mismo si desea confirmar ...
Rendimientos
fuente
Aquí hay un ejemplo simple que funciona para mí:
fuente
Aquí hay una implementación de una mano corta
if true
.Ejemplo 1
Ejemplo 2
fuente
Las respuestas existentes me parecieron confusas.
Personalmente, solo quiero tener algo que se vea y funcione como C.
Este fragmento funciona muchas veces al día en producción:
y para mantener a todos felices, probé:
Lo que también funcionó bien.
El
$snapshotEvents
evalúa los contenidos de valor de la variable. Entonces necesitas el$
.Realmente no necesitas los paréntesis, solo los encuentro útiles.
Probado en: GNU Bash, versión 4.1.11 (2) -lanzamiento
Guía Bash para principiantes , Machtelt Garrels, v1.11, 2008
fuente
()
, no son necesarios. Mi única respuesta es probarlo, parece depender de la versión de Bash, la expresión o contexto real y tal.Aquí hay una mejora en la respuesta original de miku que aborda las preocupaciones de Dennis Williamson sobre el caso en el que no se establece la variable:
Y para probar si la variable es
false
:Acerca de otros casos con un contenido desagradable en la variable, este es un problema con cualquier entrada externa alimentada a un programa.
Cualquier entrada externa debe validarse 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 .
fuente
Puedes usar shFlags .
Te da la opción de definir:
DEFINE_bool
Ejemplo:
Desde la línea de comando puede definir:
fuente
Esta es una prueba de velocidad sobre diferentes formas de probar los valores "booleanos" en Bash:
Imprimiría algo como
fuente
Alternativa: use una función
Definir la función es menos intuitivo, pero verificar su valor de retorno es muy fácil.
fuente
Bash realmente confunde el problema con los gustos de
[
,[[
,((
,$((
, etc.Todos pisando los espacios de código de los demás. Supongo que esto es principalmente histórico, donde Bash tuvo que fingir que era de
sh
vez en cuando.La mayoría de las veces, 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 mis scripts reales).Entonces puedo usar el
((
...))
operador aritmético para probar de esta manera.Tienes que ser disciplinado. Tu
testvar
debe ser bien sea a$TRUE
o$FALSE
en todo momento.En
((
...))
comparadores, no necesita lo anterior$
, lo que lo hace más legible.Puedo usar
((
...))
porque$TRUE=1
y$FALSE=0
, es decir, valores numéricos.La desventaja es tener que usar un
$
ocasionalmente:que no es tan bonito
No es una solución perfecta, pero cubre todos los casos que necesito de dicha prueba.
fuente