Evita las operaciones matemáticas en el shell de Bash

No quiero que malinterpreten esta entrada y piensen que no me gusta Bash, todo lo contrario, lo utilizo mucho luego de comprobar que puede ahorrarme la codificación de varias (entiéndase muchas) líneas de código en Python, utilizando un simple comando. Por tanto, cuando tengo un problema nuevo que resolver en el shell, simplemente diseño la secuencia de comandos adecuada y todo escribiendo una sola línea de código.

Dicho esto, hay que reconocer que Bash tiene conocimientos muy limitados de aritmética, tal es así que no entiende las operaciones con números decimales (Figura 1). Cada vez que hace una división cuyo resultado arroja un número decimal, ignora olímpicamente la parte fraccionaria. Por suerte, si por alguna ingrata razón, está obligado a hacer operaciones con números decimales, puede pedirle a otro programa que realice los cálculos por él.

Es importante saber que el motivo de este extraño comportamiento está dado porque Bash fue diseñado para tratar el contenido de las variables como cadenas alfanuméricas, por tanto, cuando una variable tiene el valor 81, lo que está guardado en esas celdas de la RAM son índices de la codificación de los símbolos “8” y “1” y nunca el número binario 0101 0001 que representa el valor 81.

Figura 1 - Bash lanza un error cuando se asigna un número real..png

Figura 1. Bash lanza un mensaje de error cuando se trata de asignar un número decimales. Elaboración Propia.

Si a pesar de leer y comprender estos tres párrafos, todavía tienes la necesidad de hacer operaciones matemáticas con Bash de cierta complejidad. Te explico cómo realizarlas a continuación:

Antes todo, los principios básicos que debes aplicar:

  • Cuando vayas a crear una variable y asignarle un valor en Bash, debes tener el cuidado de que no haya espacios a ningún lado del operador “=”. En la Figura 2 aparece un ejemplo de esto, solo puedes olvidarte de ello cuando realices la evaluación dentro del operador de expansión (()). (Este error  de principiante es la causa de que muchos programadores expertos hayan tenido que ir al médico con graves crisis de depresión y también que les haya dolido mucho la cabeza después de pasarse tres días de fiesta sin parar luego que se enteraron que el problema se solucionaba eliminando un espacio en blanco.)
  • Debes anteponer el operador $ para referirte al valor de una variable, de otro modo se confundirá con un parámetro de un comando específico (en los operadores de evaluación no son necesarios). En la Figura 1 y 2 aparecen demostraciones de esto.
Figura 2 - Utilización del operador =..png

Figura 2. Los espacios a los lados del operador de asignación provocan errores en Bash. Elaboración propia.

  • Las expresiones se procesan con los operadores de evaluación aritmética (()), $[]. Let y expr son programas que también se utilizan.  Mi sugerencia es que dejas claras tus  preferencias y no trates de usarlos todos al mismo tiempo. Estos operadores solo funcionan con valores enteros. Al final te explicaré el truco para trabajar con números decimales con bc (basic calculator). En mi caso prefiero usar (()) y como segunda opción let (Figura 3).
Figura 3 - Ejemplos $(()) $[] let..png

Figura 3. Demostración de los operadores (()), $[] y el programa let. Elaboración propia.

Teniendo en cuenta estos principios, continuemos entonces:

Operadores aritméticos básicos:

Aquí prácticamente no hay nada nuevo, tenemos los operadores +, -, *, / de toda la vida. El operador % se usa en infinidad de lenguajes de programación y es el resto de la división entera. La exponenciación (x elevado a la y) se representa como x**y.

También se utiliza los operadores de incremento y decremento ++ y –. En este caso hay que señalar que cuando se utilicen no se le puede anteponer el símbolo $ a la variable.

Figura 4 - Ejemplos de utilización de operadores aritméticos básicos..png

Figura 4. Utilización de operadores aritméticos (valores de n1=2 y n2=3). Elaboración propia.

Operadores relacionales y lógicos

En el caso de los operadores lógicos se mantienen los clásicos  && (AND), || (OR) y ! (NOT) estilo C. Sin embargo, en el caso de los operadores relacionales tenemos una variante general y otra específica para números enteros:

Variante Clásica Variante solo aplicable en comparaciones entre números enteros y fuera del operador (())
== -eq is equal to
>= -ge is greater than or equal to
> -gt is greater tan
<= -le is less than or equal to
< -lt is less tan
!= -ne is not equal to

Si eres principiante en Bash te recomiendo usar la variante clásica de los operadores relacionales (Figura 5).

Figura 5 - Ejemplos de operadores relacionales y lógicos..png

Figura 5. Utilización de Operadores relacionales y lógicos (variables n1=2 y n2=3). Elaboración propia.

 Otros operadores

Se queda fuera del alcance de esta entrada los operadores a nivel de bit y otros pero ya los trataremos en el futuro.

Operaciones con números decimales a través de bc

bc es un lenguaje de programación de cálculo numérico con precisión arbitraria, con  sintáxis similar al lenguaje de programación C. La primera versión de bc fue liberada en 1975 para Unix 6 y fue escrito por Robert Morris y  Lorinda Cherry de los Laboratorios Bell. Te recomiendo visitar la entrada de Wikipedia en inglés para profundizar, porque la información que hay en la versión en español es muy pobre.

Para usarlo desde Bash solo tenemos que escribir la sentencia matemática en el lenguaje de programación bc y enviársela mediante la redirección de entrada y salida estándar de los comandos, usando por ejemplo | (pipeline) o <<< (stdin), a continuación un ejemplo de ello:

Calculemos la raíz cuadrada de 2 con una precisión de 10 decimales:

  • Utilizando | :      q=$(echo “scale=10;  sqrt(2) ” | bc -l )
  • Utilizando <<< : q=$(bc -l <<< “scale=10;  sqrt(2)”)

Ambos métodos (no son los únicos), arrojan el mismo resultado. En este caso vemos como se utiliza bc con el parámetro –l, esto significa que le estamos indicando que cargue la biblioteca matemática estándar y establezca por defecto una escala de precisión 20. Vemos también la función sqrt() que calcula la raíz cuadrada (square root) de un número. Nótese el punto y coma intermedio, lo que refleja que se está enviando código fuente y no una expresión matemática pura.

La biblioteca matemática estándar incluye las siguientes funciones:

  • s (x): Seno de x en radianes.
  • c (x): Coseno de x en radianes.
  • a (x): Arco tangente de x en radianes.
  • l (x): Logaritmo natural de x.
  • e (x): La función exponencial e elevada a x.
  • j (n, x): Función de Bessel.

 Otros ejemplos (Figura 6):

  • pi=$(echo “scale=10; 4*a(1)” | bc -l) Calculando pi con 10 posiciones decimales de precisión.

  • raiz=$(echo “scale=5; sqrt(2)”| bc -l) Calculando la raíz cuadrada de 2 con 5 posiciones decimales de precisión.
  • op=$(echo “scale=2; (2^3)/16″| bc) Calculando la división de 2 elevado a la 3 entre 16 con 2 posiciones decimales de precisión.

Figura 6 - Ejemplos de cálculos con bc..png

Figura 6. Ejemplos de cálculo con bc. Elaboración propia.

La utilización de variables con números decimales no tiene dificultad. Solo debes anteponer en operador $. En la Figura 7 se muestra como calcular el área de un círculo. bc no dispone de una función que nos devuelva el valor de pi, por eso hay que calcularla también:

Figura 7 - Calculando el área de un círculo..png
Figura 7. Calculando el área de un círculo. Elaboración propia.

Hasta aquí la entrada de hoy, hemos podido comprender mejor las operaciones matemáticas de Bash y cómo puedes apoyarte en bc para realizar cálculos con números decimales. Al igual que bc, hay otros programas y bibliotecas que pueden usarse. Lo mejor del mundo Unix es que siempre vas a tener muchas opciones a tu favor, es solo cuestión de encontrar la que más se adapte a tus necesidades.

Te recomiendo los siguientes enlaces para que profundices sobre bc:

Espero que te haya gustado la entrada, yo por mi parte me he divertido bastante escribiéndola.

S4lud0s y h4st4 el próx1m0 p0st!!!

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s