Corregir el análisis de variables y las citas en Bash
Las citas incorrectas en el código fuente original pueden generar errores fácilmente cuando la entrada proporcionada por los usuarios no es la esperada o no es uniforme. Con el tiempo, cuando los scripts de Bash cambian, un efecto secundario imprevisto de una variable citada incorrectamente puede provocar un error incluso en código que de otro modo no se modificaría. Esto es aún más importante para aplicaciones relacionadas con la seguridad que pueden ser propensas a intentos de piratería. Aprenda a realizar citas y análisis/validación de variables correctamente desde el principio, ¡y evite muchos de estos problemas! Empecemos…
En esta serie de tutoriales aprenderá:
Cómo citar correctamente las variables de Bash
Las advertencias y los resultados de las citas incorrectas
Cómo garantizar que los valores de las variables sean los que se supone que deben ser
-
Cómo comprobar si hay valores de variables vacíos, numéricos y basados en texto
Corregir el análisis de variables y las citas en Bash
Requisitos de software y convenciones utilizadas.
Ejemplo 1: ¡Cite esas variables!
A menos que esté trabajando con valores numéricos, e incluso en ese caso a veces, es aconsejable citar siempre las variables basadas en texto al verificar la igualdad, etc. Veamos un ejemplo:
$ VAR1="a"; if [ ${VAR1} == "a" ]; then echo 'Yes!'; fi
Yes!
$ VAR1=; if [ ${VAR1} == "a" ]; then echo 'Yes!'; fi
bash: [: ==: unary operator expected
Primero configuramos VAR1
en el valor a
y posteriormente verificamos si VAR1
era igual a a
. Eso funcionó y podemos pensar que nuestro código está bien y dejarlo como está dentro de nuestro script. Sin embargo, algún tiempo después y después de muchos cambios de código, comenzamos a ver bash: [: ==: se esperaba operador unario
– un mensaje un tanto críptico que nos dice que hay algo mal con nuestro código.
La razón se muestra en el segundo ejemplo. Si de alguna manera nuestra variable está vacía, es decir, no se ha configurado correctamente (o se ha borrado desde su configuración), se nos presentará un error cuando Bash lea esto efectivamente; if [ == "a" ]
que es una declaración que no tiene mucho sentido y no se puede calcular.
Si entrecomillamos correctamente nuestra variable con comillas dobles ("
), esto no sucedería:
$ VAR1=; if [ "${VAR1}" == "a" ]; then echo 'Yes!'; fi
$
Esta vez, Bash leyó la declaración como if [ "" == "a" ]
, una declaración más agradable a la vista y al compilador de Bash. No se genera ningún resultado ya que claramente una cadena vacía no es igual a la letra a
.
Ejemplo 2: llevar las citas un poco más allá
Una vez que haya trabajado con Bash por un tiempo, aprenderá algunos de sus modismos. Uno de esos modismos es (llamémoslo privilegio (¡y seguramente es una conveniencia!)) de poder citar variables numéricas incluso si se está ejecutando una operación numérica:
$ VAR1=13; if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi
Yes!
$ VAR1=7; if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi
Aunque VAR1 esté establecido en un valor numérico, Bash aceptará "
entre comillas alrededor de VAR1 y producirá correctamente el resultado de la declaración if usando isqual
(es decir, -eq
) operación de comparación.
Sin embargo, todavía no hemos cerrado el círculo, ya que lo siguiente sigue fallando;
$ VAR1=; if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi
bash: [: : integer expression expected
Esta vez se espera una expresión entera, pero se pasó una variable vacía (es decir, ""
), y esto ciertamente no es numérico. ¿Hay alguna manera de solucionar esto? Seguro:
Ejemplo 3: comprobar la longitud cero
$ VAR1=; if [ -n "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; fi
$ VAR1=13; if [ -n "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; fi
Yes!
Aquí usamos una verificación previa para ver si la variable no tiene una longitud de cero usando la declaración condicional -n
, lo que significa que la cadena no tiene una longitud de cero. ¡Esto también podría cambiarse por lo contrario usando -z
significa la cadena tiene una longitud de cero y !
niega lo mismo, es decir, invierte el resultado:
$ VAR1=; if [ ! -z "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; fi
$ VAR1=13; if [ ! -z "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; fi
Yes!
$ VAR1=7; if [ ! -z "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; fi
$
También agregamos el ejemplo =7
aquí para mostrar cómo funciona correctamente la declaración if
. Pruebe siempre sus declaraciones y condiciones if
en una variedad de situaciones, casos de uso y excepciones genéricas (valores incorrectos, sin valor, valores impares, etc.) si desea asegurarse de que su código sea gratuito. de errores.
Ejemplo 4: una verificación casi completa
Todavía hay una deficiencia en el último ejemplo. ¿Lo recogiste? Básicamente, si pasamos valores textuales a la cadena, o la declaración if
aún falla:
$ VAR1='a'; if [ ! -z "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; fi
bash: [: a: integer expression expected
Esto se puede solucionar utilizando una subcapa, grep
y algunas expresiones regulares. Para obtener más información sobre expresiones regulares, consulte nuestros artículos sobre expresiones regulares de Bash para principiantes con ejemplos y expresiones regulares de Bash avanzadas con ejemplos. Para obtener más información sobre las subcapas de Bash, consulte nuestros artículos Subcapas de Linux para principiantes con ejemplos y Subcapas de Linux avanzadas con ejemplos.
La sintaxis no es demasiado compleja:
$ VAR1=7; if [ "$(echo "${VAR1}" | grep -o '[0-9]\+')" == "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; fi
$ VAR1=13; if [ "$(echo "${VAR1}" | grep -o '[0-9]\+')" == "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; fi
Yes!
$ VAR1='a'; if [ "$(echo "${VAR1}" | grep -o '[0-9]\+')" == "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; fi
$
Excelente. Aquí verificamos que el contenido de VAR1
sea numérico usando grep -o
(solo grep; es decir, grep solo la parte que coincide con la cadena de búsqueda, que en este caso es una expresión regular). Seleccionamos cualquier carácter numérico de 0-9
y este una o más veces (como lo indica el calificador \+
al [ 0-9]
rango de selección). Luego, intentamos hacer coincidir este texto parte coincidente grep con la variable original. ¿Es lo mismo? En caso afirmativo, entonces nuestra variable consta únicamente de números.
Cuando expandimos un poco nuestra declaración if
externa para incluir una cláusula else
que nos dirá si una variable no es numérica, y cuando intentamos pasar ' a'
como entrada vemos que las distintas entradas se analizan correctamente;
$ VAR1=7; if [ "$(echo "${VAR1}" | grep -o '[0-9]\+')" == "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; else echo 'Variable not numeric!'; fi
$ VAR1=13; if [ "$(echo "${VAR1}" | grep -o '[0-9]\+')" == "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; else echo 'Variable not numeric!'; fi
Yes!
$ VAR1='a'; if [ "$(echo "${VAR1}" | grep -o '[0-9]\+')" == "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; else echo 'Variable not numeric!'; fi
Variable not numeric!
Entonces ahora tenemos una línea perfecta para nuestro código, ¿no? No… Todavía nos falta algo… ¿Ves qué?
Ejemplo 5: un control completo
¿Viste el problema? ¡Aún no hemos comprobado si hay una variable vacía!
$ VAR1=''; if [ "$(echo "${VAR1}" | grep -o '[0-9]\+')" == "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; else echo 'Variable not numeric!'; fi
bash: [: : integer expression expected
Ay. Espero que a esta altura ya entiendas por qué menciono regularmente en mis artículos que siempre revises tus creaciones de código de una forma u otra. Claro, Bash se presta para secuencias de comandos rápidas y fáciles, pero si desea asegurarse de que todo continúe funcionando correctamente al cambiar sus secuencias de comandos o agregar código adicional, querrá asegurarse de que sus pruebas, entradas y salidas estén limpias y claramente definidas. . La solución es fácil:
$ VAR1=''; if [ ! -z "${VAR1}" -a "$(echo "${VAR1}" | grep -o '[0-9]\+')" == "${VAR1}" ]; then if [ "${VAR1}" -eq 13 ]; then echo 'Yes!'; fi; else echo 'Variable not numeric!'; fi
Variable not numeric!
Aquí, usando la primera declaración if
, agregamos una condición adicional para que la variable VAR1
no (!
) sea una variable de longitud cero. Esto funciona bien dada la configuración actual, ya que la segunda parte de la primera declaración if
aún puede continuar independientemente del contenido de VAR1
.
Conclusión
En este artículo, analizamos cómo citar y analizar/evaluar variables correctamente, y exploramos lo complejo que era escribir una pieza de código Bash perfecta para verificar variables. Aprender cómo hacer estas cosas correctamente desde el principio limitará en gran medida la cantidad de posibles errores que pueden introducirse por accidente.
¡Disfruta y cita dos veces esas variables! 🙂