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.
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.
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.
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.
La -n
opció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 if
declaraciones. 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 $month
variable 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 $month
variable 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 chmod
comando :
chmod +x estaciones.sh
Podemos probar el script por
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
Eso parece funcionar como se esperaba. Hagamos que Bash verifique la sintaxis de nuestro script. Hacemos esto invocando la -n
opción (noexec) y pasando el nombre de nuestro script.
bash -n ./temporadas.sh
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 then
de la primera if
clá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
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.
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 then
en nuestro script e intentemos otra cosa. Eliminaremos el corchete de apertura “[” de la primera if
clá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
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.
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 test
comando .
Bash no comprueba el uso de programas externos cuando valida un script.
ShellCheck requiere instalación. Para instalarlo en Ubuntu, escriba:
sudo apt install shellcheck
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
En Manjaro y distribuciones similares basadas en Arch , usamos pacman
:
sudo pacman -S shellcheck
Intentemos ejecutar ShellCheck en nuestro script.
shellcheck temporadas.sh
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.
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
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 read
comando sin la -r
opció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.
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?
El mundo del gaming ha experimentado un crecimiento exponencial en los últimos años. La…
Stokkete/Shutterstock.com ¿Sigue utilizando una unidad flash USB obsoleta para almacenar sus archivos? ¿Por qué no…
LG Los fabricantes siempre intentan mejorar el rendimiento de imagen de los monitores. Como resultado,…
Patty Chan/Shutterstock.com Si cree en lo que ve en las redes sociales, puede pensar en…
Seksan.TH/Shutterstock.com Los servicios de suscripción como Netflix, Game Pass y Spotify nos permiten consumir tantas…
fatmawati achmad zaenuri/Shutterstock El acceso a Internet, oa cualquier otra red, se rige por la…