martes, 2 de marzo de 2021

scripts en Bash... para torpes (V)

Retomo estos temas… y vayamos complicando las cosas… aunque yo solo toque cuestiones consideradas ‘sencillas’. Hoy vamos a hablar, por si algún día lo necesitas (o para saber de qué va la cosa e ir mejorando la ‘culturilla en Bash) de cómo plantear operaciones aritméticas o de cómo comparar cadenas, o variables, en Bash.
5- Operaciones aritméticas y de comparación, o lógicas, en Bash

En Bash se pueden utilizar las operaciones aritméticas entre dos variables utilizando los conocidos signos +, -, * y /. Y además se emplea el signo % para conocer el resto de una división, porque al dividir solo te sale el cociente como número entero. Es que Bash solo soporta, internamente, números enteros, no operaciones con decimales. Pero luego veremos cómo solventarlo.

Lo que interesa es saber cómo se declara una operación aritmética ‘como variable’. Y hay varias formas de hacerlo: para cierto nivel de conocimiento se declara anteponiendo «declare» (que permite definir algunas propiedades de la variable). Otras formas son...

con «let» con «expr» con doble paréntesis
sumar let SUM=$X+$Y expr $X + $Y # SUM SUM=$(($X + $Y))
restar let RES=$X-$Y expr $X - $ # RES RES=$(($X - $Y))
multiplicar let PROD=$X*$Y expr $X * $Y # PROD PROD=$(($X + $Y))
dividir let DIV=$X/$Y
let resto=$X%$Y
expr $X / $Y # DIV
expr $X % $Y # resto
DIV=$(($X / $Y))
resto=$(($X % $Y))

Por supuesto, para obtener (ver) el resultado habría que añadir
&& echo $SUM (o la variable que sea)
Mi consejo es emplear el doble paréntesis, que es lo más habitual. Aunque parezca sencilla, «let» tiene sus complicaciones, y «expr» está en desuso. Y ya dije que «declare» es para otro nivel de conocimiento.
Por aclararlo, lo de los dobles paréntesis es porque ($var1 + $var2) define el conjunto, o cadena, y el segundo paréntesis es el que se emplea para declarar la variable de la operación aritmética. Y se pueden poner, si llega el caso, más paréntesis. Eso si, sabiendo que hay que ‘cerrarlos’ bien.

Sigamos: decía al principio que Bash solo admitía números enteros.
Pero...

Trabajar con decimales , con « bc »
El comando « bc » es todo un mundo (ver man bc). Hablando de operaciones aritméticas, podemos utilizar su opción ‘scale’ para dar un output con decimales.
La sintaxis (para una división) es esta:
RESULTADO=$(echo "scale=3; $X / $Y" | bc)
donde ‘scale=3 indica que queremos el resultado con 3 decimales: Y, con la tubería a « bc », obtenerlo en el resultado. Vamos a verlo (por consola) con los ejemplos/modelos con números (por cierto, en Bash, los decimales siempre con ‘punto’, no con ‘coma’. Para 2 decimales...
SUM=$(echo "scale=2; 3.45+8.23" | bc) && echo $SUM
PROD=$(echo "scale=2; 3.45*8.2" | bc) && echo $PROD
DIV=$(echo "scale=2; 345/36" | bc) && echo $DIV

(NOTA: los números, por supuesto, pueden sustituirse por variables $num1, $num2. Incluso ejecutar el script introduciéndole dos números cualesquiera como argumentos (dividendo y divisor, en los cocientes), bastando poner entonces (y para siempre) $1 y $2 (los dos argumentos).

Y un truquito final: Si un número da resultado negativo, podríamos cambiarle de signo ‘trucando’ esa variable. Basta que la invoquemos entre {claves} y añadiendo #- (almohadilla y signo menos). Se entiende con un ejemplo:
DIF=$((43 - 58)) && echo ${DIF#-}
Así que, como resumen de las operaciones aritméticas, estas son las sintaxis:
Operaciones Aritméticas
SUM=$(($num1 + $num2)) && echo $SUM
DIF=$(($num1 - $num2)) && echo $DIF
para valor absoluto en la resta…
DIFabs=$(($num1 - $num2)) && echo ${DIF#-}

Con decimales (por ejemplo)...
SUM=$(echo "scale=2; 3.45+8.23" | bc) && echo $SUM
DIF=$(echo "scale=2; 3.45-8.23" | bc) && echo $SUM
PROD=$(echo "scale=2; 3.45*8.2" | bc) && echo $PROD
DIV=$(echo "scale=2; 345/8.2" | bc) && echo $DIV


Las operaciones lógicas
Otro aspecto de interés es el de las operaciones lógicas (comparar X con Y). Aquí tenemos que saber distinguir entre operaciones con números y operaciones con funciones. Una cuestión importante: por defecto, Bash trata las variables como cadena de texto (independientemente de si declaran un texto, o un número). Y, dicho esto, este cuadro indica cómo hay que expresar las comparaciones…

Entre números
(y solo números)
X <comparación> Y Entre cadenas textos
(o no solo números)
(less than)
-lt Menor que <
(less than or equal) -le Menor o igual que <=
(equal) -eq Igual
=
(greater than or equal) -ge Igual o mayor que
=>
(greater than)
-gt Mayor que
>
(not equal) -ne Distinto que
!


Idéntico a ==


que se expresan, en principio, entre corchetes:
if [ 9 -lt 10 ] if [ "$name1" = "$name2" ]
(es importante dejar esos espacios en blanco. A veces se ven dobles corchetes, quizás para englobar las cadenas. Y vuelvo a insistir que todo se ve mucho mejor con letras ‘monospace’
Un ejemplo, que me parece interesante.
Para saber si un número (o un variable numérica) está dentro de un rango de números podemos emplear esto (lo pongo así, en vez de como script, para poder verlo copiando y pegando, directamente, en consola):

read -p "introduce un número del 1 al 10: " num && if [ "$num" -ge 0 -a "$num" -le 7 ]; then echo "si, el $num entra en el rango fijado"; else echo "lo siento, el $num no entra en el rango"; fi
(al final explico lo que significa ese operador ‘-a’ y, próximamente, lo del condicional ‘if’)

Y ya acabo con unas cuantas ideas sueltas (sin desarrollar) por aquello de que, si se ven alguna vez, sepamos de qué va la cosas: Hay algunas otras expresiones, como « == » (doble signo de igual) que se usa para comparar que dos cadenas sean ‘literalmente’ iguales.
A veces se usan los operadores ‘-a’ (and) y ‘-o’ (or). Estos operadores equivalen a && y || cuando se usan con doble corchete: [[ condition1 && condition2 ]].
(Así, exp1 -a exp2 que devuelve verdadero si ambas exp1 y exp2 son verdaderas y exp1 -o exp2 que devuelve verdadero si alguna de las expresiones son verdaderas)
Y decir que los resultados true’ y ‘falsedevuelven 0 y 1, respectivamente.

Pero ya estamos hablando de cosas de cierto nivel, y esto es… ‘para torpes’. 

 

Ir al Sumario (del tema)

 

 

No hay comentarios:

Publicar un comentario