¿Cuál es la mejor práctica para representar un valor booleano en un script de shell?

15

Sé que hay valores booleanos bash, pero nunca los veo en ningún lado.

Quiero escribir un contenedor para alguna información a menudo buscada en mi máquina, por ejemplo, si esta unidad USB particular está insertada / montada.

¿Cuál sería la mejor práctica para lograr eso?

  • ¿Una cuerda?

    drive_xyz_available=true
  • ¿Un número (0 para verdadero, ≠ 0 para falso)?

    drive_xyz_available=0    # evaluates to true
  • ¿Una función?

    drive_xyz_available() { 
        if available_magic; then 
                return 0 
        else 
                return 1 
        fi
    }

Principalmente me pregunto qué esperarían otras personas que quisieran usar el envoltorio. ¿Esperarían un valor booleano, un comando como variable o una función para llamar?

Desde el punto de vista de la seguridad, creo que la segunda opción es la más segura, pero me encantaría escuchar sus experiencias.

Minix
fuente
3
help true ; help false ; help exit
Costas
3
@Costas ¿Te importaría elaborar?
Minix

Respuestas:

2
bool(){ return "$((!${#1}))"; }

if bool "$var"
then : do true
else : do false

Simplemente establezca una variable en cualquier cosa que no sea nula para que funcione lo anterior, aunque [ -n "$var" ]sería más corto, si no tan obvio.

En general, cuando un script interpreta que una variable de entorno es verdadera o falsa, interpretará cualquier valor como verdadero (y, a veces, usará dicho valor para configurar alguna opción) o un valor nulo como falso.

Lo anterior devuelve el !notvalor booleano de la len de su primer argumento: si el argumento contiene cualquier número de caracteres que no sea 0, devuelve 0, de lo contrario, si no tiene ningún carácter, devuelve 1. Esta es la misma prueba con la que puede realizar [ -n "$var" ], básicamente , pero simplemente lo envuelve en una pequeña función llamada bool().

Por lo general, así es como funciona una variable de bandera . Por ejemplo:

[ -d "$dir" ] || dir=

Donde otras partes de un script solo necesitan buscar algún valor $dirpara evaluar su utilidad. Esto también es útil cuando se trata de la sustitución de parámetros, ya que los parámetros se pueden expandir a los valores predeterminados para completar los valores vacíos o no establecidos, pero de lo contrario se expandirán a un valor preestablecido como ...

for set in yes ''
do echo "${set:-unset or null}"
done

... que imprimiría ...

yes
unset or null

Por supuesto, también es posible hacer lo contrario, :+pero eso solo puede darle un valor predeterminado predeterminado o nada en absoluto, mientras que el formulario anterior puede darle un valor o un valor predeterminado.

Y así, con respecto a las tres opciones, cualquiera podría funcionar dependiendo de cómo elija implementarlo. El retorno de la función es de autocomprobación, pero, si ese retorno necesita guardarse por algún motivo, deberá colocarse en una variable. Depende del caso de uso: ¿es el valor booleano que desea evaluar una prueba una vez y listo? Si es así, realice la función, de lo contrario, cualquiera de los otros dos probablemente sea necesario.

mikeserv
fuente
1
No creo que estés respondiendo mi pregunta. No estoy preguntando cómo se pueden usar los booleanos en un script de shell, pero de qué manera es el más común y que otro usuario esperaría. Si mi pregunta no está clara, me encantaría editarla. También una breve explicación de lo que hace su respuesta sería agradable. Gracias.
Minix
@Minix ¿Algo mejor?
mikeserv
Generalmente asigno trueo falsea una variable, entonces puedes hacerif $variable; then ...
wurtel
@wurtel, que se basa en el valor predeterminado $IFS, y si el valor de la var puede contener información del usuario de cualquier tipo, también en buena suerte. Si no se desconoce el valor, entonces hay poca necesidad de probarlo. Puede hacerlo de manera más segura if ${var:+":"} false; thencuando trabaja con valores nulos / no nulos booleanos. Pero eso rara vez es más útil que[ -n "$var" ] &&
mikeserv
Si comienzo mi script con variable=falsey luego lo configuro en verdadero de acuerdo con cualquier condición (como lo haría al usar una variable en C), entonces no hay ningún problema, ¿Cuál es su obsesión con los valores IFS variables y los valores de variables aleatorias, etc. de todos modos? .
wurtel
4

En bashcada variable hay esencialmente una cadena (o una matriz o una función, pero hablemos de las variables regulares aquí).

Las condiciones se analizan en función de los valores de retorno de los comandos de prueba: el valor de retorno no es una variable, es un estado de salida. Al evaluar if [ ... ]o if [[ ]]o if grep somethingni nada de eso, el valor de retorno 0 (no cadena de 0, pero el código de salida 0 = éxito) que significa la verdadera y la falsa media de descanso (por lo que, exactamente lo contrario de lo que estamos acostumbrados en lenguajes de programación compilado, pero debido a que hay una forma de tener éxito y muchas formas de fracasar, y el resultado esperado de la ejecución suele ser exitoso, 0 se usa como el resultado predeterminado más común si nada sale mal). Esto es muy útil porque cualquier binario se puede usar como prueba; si falla, es falso, de lo contrario es cierto.

truey los falseprogramas (generalmente anulados por los componentes incorporados) son solo pequeños programas útiles que no hacen nada: truelogran no hacer nada y salen con 0, mientras falseintentan no hacer nada y "fallan", saliendo con 1. Suena inútil pero es muy útil para las secuencias de comandos.

En cuanto a cómo transmitir la veracidad, depende de usted. Es bastante común usar "y" o "sí" para la verdad y el uso if [ x"$variable" = x"yes" ](se agrega la cadena ficticia xporque si $variableresulta ser de longitud cero, esto protege contra la creación de un comando falso if [ = "yes" ]que no analiza). También puede ser útil simplemente usar una cadena vacía para falso, y usar [ -z "$variable ]para probar si es de longitud cero (o -npara que no sea cero).

De todos modos, es bastante raro que realmente necesite pasar valores booleanos bash: es mucho más común simplemente exiten caso de falla o devolver un resultado útil (o cero si algo sale mal y probar una cadena vacía), y la mayoría de los casos pueden prueba de falla directamente desde el estado de salida.


En su caso, desea una función que actúe como cualquier otro comando (por lo tanto, devuelve 0 en caso de éxito), por lo que su última opción parece ser la correcta.

Además, es posible que ni siquiera necesite una returndeclaración. Si la función es lo suficientemente simple, puede usar el hecho de que simplemente devuelve el estado del último comando ejecutado en la función. Entonces su función puede ser simplemente

drive_xyz_available() {
   [ -e /dev/disk/by-uuid/whatever ]
}

si está probando la existencia de un nodo de dispositivo (¿o grep /proc/mountspara verificar si está montado?).

Orión
fuente
Es un resumen muy agradable, gracias por tomarse el tiempo para escribirlo. ¿Puedo deducir de su último párrafo que consideraría la opción de drive_xyz_available()ser la más común?
Minix
¿Puedes dar algunos ejemplos para el y = truecaso común ? En mi experiencia, la mayoría de los scripts de envoltura prueban cualquier valor no nulo para considerarlo verdadero, al menos en lo que respecta a las variables de entorno interpretadas. De lo contrario, ignoran por completo los coches cáscara.
mikeserv
3
La cadena ficticia para la ifprueba no es necesaria si se cita la variable; if [ "$variable" = "yes" ]funciona bien incluso si $ variable no está establecida.
daniel kullmann
-2

Básicamente, cualquier número que no sea 0 es verdadero y 0 es falso. Motivo para devolver valores como 0 para un final exitoso de un script o cualquier otro número para identificar diferentes tipos de errores.

$? devolverá el código de salida del comando / ejecutable anterior, siendo 0 exitoso y cualquier otro número el error que ha sido devuelto.

Entonces usaría ese método para verdadero / falso. if (( ! $? ));then OK;else NOOK;fi

YoMismo
fuente
Escribiré uno para la última opción, entonces. Gracias.
Minix
55
Un número distinto de cero es falso en realidad, y cero es verdadero. Solo mira la salida de true; echo $?y false; echo $?.
Ruslan
@Ruslan. ¿Verificaste el resultado de mi comando? Supongo que no lo hiciste, de lo contrario no hubieras dicho lo que hiciste. 0 es falso, cualquier otro número es verdadero, razón para negar !el resultado para que sea VERDADERO. El resultado de un comando es 0 cuando ha finalizado correctamente, lo que no significa que 0 sea verdadero. La palabra truepuede ser 0, pero 0 nunca es verdadero como lo ifdemuestra la condición.
YoMismo
Eso es lo mismo que decir que en C / C ++, 0es trueporque if(!x){True();}else{False();}llamará True()cuándo x==0. Pero la verificación correcta no sería !x, sino más bien !!x.
Ruslan
Estás muuuuuy mal. No estoy hablando de qué y qué orden tiene lo que escribas después de ifque simplemente diga el hecho de que aquí (en bash, o ksh, o tsh, o ...) como en C / C ++ a 0 es FALSO, cualquiera otro número es VERDADERO, como puede leer en el siguiente enlace, las implementaciones iniciales de C no proporcionaron ningún tipo booleano, definiéndose como ints donde 0 era FALSO y 1 VERDADERO en.wikipedia.org/wiki/Boolean_data_type .
YoMismo