Empecé a aprender Bash con la ayuda de la IA, un ChatGPT preparado para eso. Ahora mismo estoy repasando condicionales combinadas con operadores lógicos, de prueba, de comparación, etc.
Mi consulta en concreto es sobre un script que, con base en lo que entiendo del funcionamiento de Bash, debería dar error como salida, pero funciona y no sé porqué. Aquí el código:
read -p "Ingresa la cantidad de GB: " gb
if [[ -z "$gb" || "$gb" =~ ^[0-9]+$ ]] && ((gb > 0)); then
mb=$((gb*1024))
kb=$((mb*1024))
echo "$gb GB(s) es equivalente a $mb MBs y a $kb KBs."
else
echo "Ingresa un número entero mayor que cero."
fi
Explico mi razonamiento:
- La primera condición
-z "$gb" solamente es verdadera si el valor de la variable $gb está vacío.
- Si el punto 1. se cumple, no se ejecuta la segunda condición
"$gb" =~ ^[0-9]+$ ni la tercera ((gb > 0)). La segunda porque está bajo una disyunción exclusiva ||, y la tercera porque no evalúa eso; es irrelevante.
- Si el punto 1 se cumple, se ejecuta el bloque
then y la variable pasa a la operación aritmética. Esto daría error, porque no se puede operar con una variable vacía.
- Si el punto 3 se cumple, debería aparecer un mensaje de error, porque el escenario donde no se coloca valor a la variable no está consignado en el código.
En lugar de eso, se ejecuta el bloque else. Pero para que eso suceda, según entiendo, la primera condición debería ser -n "$gb" (es V si la variable no está vacía).
Traté de explicarle mi duda a la IA, pero parece que solo es buena para corregir errores de sintaxis, no explicando las razones de las cosas.
Tienes:
(A || B) && C
Donde:
A = -z "$gb"
B = "$gb" =~ ^[0-9]+$
C = (( gb > 0 ))
Supongamos que no se le pasa ningún input al script.
-z "$gb" es true porque la variable está vacía.
Termina el bloque [[ ]].
Como A ya es true, podríamos ver esa parte así:
[[ true ]]
El script evalúa al mismo tiempo:
&& (( gb > 0 ))
No le pasamos nada a gb, entonces Bash lo interpreta como 0.
0 > 0 → false
Terminamos con:
[[ true ]] && false
Mirando una tabla de lógica AND:
true AND false = false
Por lo tanto, la condición completa es false.
El script entonces entra al bloque else.
Edit:
|| es un OR, no un XOR (no es una disyunción exclusiva).
- Siempre se va a evaluar
&& (( gb > 0 )), porque forma parte de la condición completa.
1 me gusta
Buenas,
Yo creo que puedes quitar la primera validación de cadena vacía. Si ya estás validando que la cadena sean números, no veo para qué quieres validar que no sea cadena vacía.
Es decir, que sea solo ńumeros && mayor que 0:
if [[ "$gb" =~ ^[0-9]+$ ]] && ((gb > 0)); then
No obstante, siempre que hay que hacer temas de operaciones numéricas prefiero usar Perl o Python. Aunque es cierto que para operaciones complejas también puedes usar “bc” en Bash.
Un saludo
1 me gusta
Va, me queda claro donde fallé. No sabía que se interpretaba como cero. Gracias!
yep, pero creo que solo en contextos aritméticos (( ... )) las variables vacías se interpretan como 0.
La validación de variable vacía fue sugerencia de la IA, pero no veo razón para no usarla. O más bien, usar una validación de variable no vacía (creo que eso tiene más sentido en este caso). ¿Por qué?Supongo que es mejor cuando el código no da error, aunque este solo sea un ejercicio de repaso.
Entiendo, voy a hacer la prueba con otro script o consultarlo con la IA para dejarlo anotado.
De todas formas, creo que la condición 1 no sirve en este caso. Debería evaluar que la variable no esté vacía.