Cómo validar la sintaxis de un script Bash de Linux antes de ejecutarlo

Una terminal Linux en la pantalla de un portátil sobre un fondo rojo.
fatmawati achmad zaenuri/Shutterstock

Los errores y errores tipográficos en los scripts de Linux Bash pueden hacer cosas terribles cuando se ejecuta el script. Aquí hay algunas formas de verificar la sintaxis de sus scripts incluso antes de ejecutarlos.

Esos molestos bichos

Escribir código es difícil. O, para ser más precisos, es difícil escribir código no trivial sin errores. Y cuantas más líneas de código haya en un programa o script, más probable es que haya errores en él.

El lenguaje en el que programa tiene una relación directa con esto. La programación en ensamblador es mucho más difícil que la programación en C, y la programación en C es más desafiante que la programación en Python . Cuanto más bajo sea el lenguaje en el que está programando, más trabajo tendrá que hacer usted mismo. Python puede disfrutar de rutinas de recolección de basura incorporadas, pero C y ensamblador ciertamente no.

Escribir scripts de shell de Linux plantea sus propios desafíos. Con un lenguaje compilado como C, un programa llamado compilador lee su código fuente (las instrucciones legibles por humanos que escribe en un archivo de texto) y lo transforma en un archivo ejecutable binario. El archivo binario contiene las instrucciones del código de máquina que la computadora puede entender y actuar.

El compilador solo generará un archivo binario si el código fuente que está leyendo y analizando obedece la sintaxis y otras reglas del lenguaje. Si escribes una  palabra reservada —una de las palabras de comando del lenguaje— o un nombre de variable incorrectamente, el compilador arrojará un error.

Por ejemplo, algunos lenguajes insisten en que declare una variable antes de usarla, otros no son tan quisquillosos. Si el lenguaje en el que está trabajando requiere que declare variables pero olvida hacerlo, el compilador arrojará un mensaje de error diferente. A pesar de lo molestos que son estos errores de tiempo de compilación, detectan muchos problemas y lo obligan a solucionarlos. Pero incluso cuando tienes un programa que no tiene  errores sintácticos  , no significa que no haya errores en él. Lejos de ahi.

Los errores que se deben a  fallas lógicas  suelen ser mucho más difíciles de detectar. Si le dice a su programa que sume dos y tres pero usted realmente quería que sumara dos y dos, no obtendrá la respuesta que esperaba. Pero el programa está haciendo lo que ha sido escrito para hacer. No hay nada malo con la composición o sintaxis del programa. El problema eres tú. Has escrito un programa bien formado que no hace lo que querías.

La prueba es difícil

Probar a fondo un programa, incluso uno simple, requiere mucho tiempo. Ejecutarlo varias veces no es suficiente; realmente necesita probar todas las rutas de ejecución en su código, para que se verifiquen todas las partes del código. Si el programa solicita una entrada, debe proporcionar un rango suficiente de valores de entrada para probar todas las condiciones, incluida la entrada inaceptable.

Relacionado:  Cómo desactivar las sugerencias de comando de repetición del Asistente de Google

Para lenguajes de nivel superior, las pruebas unitarias y las pruebas automatizadas ayudan a que las pruebas exhaustivas sean un ejercicio manejable. Entonces, la pregunta es, ¿hay alguna herramienta que podamos usar para ayudarnos a escribir scripts de shell Bash sin errores?

La respuesta es sí, incluido el propio shell Bash.

Uso de Bash para verificar la sintaxis del script

La -nopción Bash (noexec) le dice a Bash que lea un script y verifique si hay errores sintácticos, sin ejecutar el script. Dependiendo de lo que pretenda hacer su secuencia de comandos, esto puede ser mucho más seguro que ejecutarlo y buscar problemas.

Aquí está el script que vamos a comprobar. No es complicado, es principalmente un conjunto de ifdeclaraciones. Solicita y acepta un número que representa un mes. El guión decide a qué estación pertenece el mes. Obviamente, esto no funcionará si el usuario no proporciona ninguna entrada o si proporciona una entrada no válida como una letra en lugar de un dígito.

#! /bin/bash

read -p "Ingrese un mes (1 a 12): " mes

# ingresaron algo?
si [ -z "$mes" ]
entonces
  echo "Debe ingresar un número que represente un mes."
  salida 1
fi

# ¿Es un mes válido?
if (( "$mes" < 1 || "$mes" > 12)); entonces
  echo "El mes debe ser un número entre 1 y 12."
  salida 0
fi

# es un mes de primavera?
if (( "$mes" >= 3 && "$mes" < 6)); entonces
  echo "Ese es un mes de primavera".
  salida 0
fi

# es un mes de verano?
if (( "$mes" >= 6 && "$mes" < 9)); entonces
  echo "Ese es un mes de verano".
  salida 0
fi

# ¿Es un mes de otoño?
if (( "$mes" >= 9 && "$mes" < 12)); entonces
  echo "Ese es un mes de otoño".
  salida 0
fi

# debe ser un mes de invierno
echo "Ese es un mes de invierno".
salida 0

Esta sección verifica si el usuario ha ingresado algo. Comprueba si la $monthvariable está desarmada.

si [ -z "$mes" ]
entonces
  echo "Debe ingresar un número que represente un mes."
  salida 1
fi

Esta sección verifica si han ingresado un número entre 1 y 12. También atrapa la entrada no válida que no es un dígito, porque las letras y los símbolos de puntuación no se traducen en valores numéricos.

# ¿Es un mes válido?
if (( "$mes" < 1 || "$mes" > 12)); entonces
  echo "El mes debe ser un número entre 1 y 12."
  salida 0
fi

Todas las demás cláusulas If comprueban si el valor de la $monthvariable está entre dos valores. Si es así, el mes pertenece a esa estación. Por ejemplo, si el mes ingresado por el usuario es 6, 7 u 8, es un mes de verano.

# es un mes de verano?
if (( "$mes" >= 6 && "$mes" < 9)); entonces
  echo "Ese es un mes de verano".
  salida 0
fi

Si desea trabajar con nuestros ejemplos, copie y pegue el texto del guión en un editor y guárdelo como «temporadas.sh». Luego haga que el script sea ejecutable usando el chmodcomando :

chmod +x estaciones.sh

Establecer el permiso ejecutable en un script

Podemos probar el script por

  • Proporcionar ninguna entrada en absoluto.
  • Proporcionar una entrada no numérica.
  • Proporcionar un valor numérico que esté fuera del rango de 1 a 12.
  • Proporcionar valores numéricos dentro del rango de 1 a 12.
Relacionado:  ¿Dónde está la carpeta de música en una Mac?

En todos los casos, iniciamos el script con el mismo comando. La única diferencia es la entrada que proporciona el usuario cuando lo promueve el script.

./temporadas.sh

Probar un script con una variedad de entradas válidas e inválidas

Eso parece funcionar como se esperaba. Hagamos que Bash verifique la sintaxis de nuestro script. Hacemos esto invocando la -nopción (noexec) y pasando el nombre de nuestro script.

bash -n ./temporadas.sh

Usando Bash para probar la sintaxis de un script

Este es un caso de “ninguna noticia es una buena noticia”. Devolvernos silenciosamente al símbolo del sistema es la forma en que Bash dice que todo parece estar bien. Saboteemos nuestro script e introduzcamos un error.

Eliminaremos el thende la primera ifcláusula.

# ¿Es un mes válido?
if (( "$mes" < 1 || "$mes" > 12)); # "entonces" ha sido eliminado
  echo "El mes debe ser un número entre 1 y 12."
  salida 0
fi

Ahora ejecutemos el script, primero sin y luego con la entrada del usuario.

./temporadas.sh

Probar un script con entradas no válidas y válidas

La primera vez que se ejecuta el script, el usuario no ingresa un valor y, por lo tanto, el script finaliza. La sección que hemos saboteado nunca se alcanza. El script finaliza sin un mensaje de error de Bash.

La segunda vez que se ejecuta el script, el usuario proporciona un valor de entrada, y la primera cláusula if se ejecuta para verificar la cordura de la entrada del usuario. Eso desencadena el mensaje de error de Bash.

Tenga en cuenta que Bash verifica la sintaxis de esa cláusula, y todas las demás líneas de código, porque no le importa la lógica del script. No se le solicita al usuario que ingrese un número cuando Bash verifica el script, porque el script no se está ejecutando.

Las diferentes rutas de ejecución posibles del script no afectan la forma en que Bash verifica la sintaxis. Bash se abre camino de manera simple y metódica desde la parte superior del script hasta la parte inferior, verificando la sintaxis de cada línea.

La utilidad ShellCheck

Un linter, llamado así por una herramienta de verificación de código fuente C del apogeo de Unix , es una herramienta de análisis de código que se utiliza para detectar errores de programación, errores de estilo y uso sospechoso o cuestionable del lenguaje. Los linters están disponibles para muchos lenguajes de programación y son famosos por ser pedantes. No todo lo que encuentra un linter es un error  per se , pero cualquier cosa que le llame la atención probablemente merezca atención.

ShellCheck es una herramienta de análisis de código para scripts de shell. Se comporta como un linter para Bash.

Volvamos a poner nuestra palabra reservada faltante thenen nuestro script e intentemos otra cosa. Eliminaremos el corchete de apertura “[” de la primera ifcláusula.

# ingresaron algo?
if -z "$mes" ] # corchete de apertura "[" eliminado
entonces
  echo "Debe ingresar un número que represente un mes."
  salida 1
fi

si usamos Bash para verificar el script, no encuentra ningún problema.

bash -n estaciones.sh
./temporadas.sh

Un mensaje de error de un script que pasó la verificación de sintaxis sin problemas detectados

Pero cuando intentamos ejecutar el script, vemos un mensaje de error. Y, a pesar del mensaje de error, el script continúa ejecutándose. Es por eso que algunos errores son tan peligrosos. Si las acciones realizadas más adelante en la secuencia de comandos se basan en una entrada válida del usuario, el comportamiento de la secuencia de comandos será impredecible. Potencialmente podría poner en riesgo los datos.

Relacionado:  Cómo evitar que las personas instalen extensiones en Chrome

La razón por la que la opción Bash -n(noexec) no encuentra el error en el script es que el corchete de apertura “[” es un programa externo llamado [. No es parte de Bash. Es una forma abreviada de usar el testcomando .

Bash no comprueba el uso de programas externos cuando valida un script.

Instalación de ShellCheck

ShellCheck requiere instalación. Para instalarlo en Ubuntu, escriba:

sudo apt install shellcheck

Instalación de shellcheck en Ubuntu

Para instalar ShellCheck en Fedora, use este comando. Tenga en cuenta que el nombre del paquete está en mayúsculas y minúsculas, pero cuando ejecuta el comando en la ventana del terminal, todo está en minúsculas.

sudo dnf instalar ShellCheck

Instalación de shellcheck en Fedora

En Manjaro y distribuciones similares basadas en Arch , usamos pacman:

sudo pacman -S shellcheck

Instalando shellcheck en Manjaro

Uso de ShellCheck

Intentemos ejecutar ShellCheck en nuestro script.

shellcheck temporadas.sh

Comprobación de un script con ShellCheck

ShellCheck encuentra el problema y nos lo informa, y ​​proporciona un conjunto de enlaces para obtener más información. Si hace clic con el botón derecho en un enlace y elige «Abrir enlace» en el menú contextual que aparece, el enlace se abrirá en su navegador.

Informes de errores y advertencias de ShellCheck

ShellCheck también encuentra otro problema, que no es tan grave. Se informa en texto verde. Esto indica que es una advertencia, no un error absoluto.

Corrijamos nuestro error y reemplacemos el “[.” Una estrategia de corrección de errores es corregir primero los problemas de mayor prioridad y luego trabajar con los problemas de menor prioridad, como las advertencias.

Reemplazamos el «[» faltante y ejecutamos ShellCheck una vez más.

shellcheck temporadas.sh

Comprobación de un script por segunda vez con ShellCheck

El único resultado de ShellCheck se refiere a nuestra advertencia anterior, así que está bien. No tenemos problemas de alta prioridad que necesiten solución.

La advertencia nos dice que usar el readcomando sin la -ropción (leer tal cual) hará que cualquier barra invertida en la entrada se trate como caracteres de escape. Este es un buen ejemplo del tipo de salida pedante que puede generar un linter. En nuestro caso, el usuario no debería ingresar una barra invertida de todos modos, necesitamos que ingrese un número.

Advertencias como esta requieren un juicio por parte del programador. ¿Hacer el esfuerzo de arreglarlo o dejarlo como está? Es una solución simple de dos segundos. Y evitará que la advertencia sature la salida de ShellCheck, por lo que también podemos seguir su consejo. Agregaremos una «r» a la opción de las banderas en el read comando y guardaremos el script.

read -pr "Ingrese un mes (1 a 12): " mes

Ejecutar ShellCheck una vez más nos da un certificado de buena salud.

No hay errores ni advertencias informados por ShellCheck

ShellCheck es su amigo

ShellCheck puede detectar, informar y asesorar sobre una amplia gama de problemas . Echa un vistazo a su galería de código incorrecto , que muestra cuántos tipos de problemas puede detectar.

Es gratis, rápido y elimina gran parte del dolor de escribir scripts de shell. ¿Que es no gustar?