set -u uso no funciona como se esperaba

12

Estoy aprendiendo cómo usar de manera eficiente diferentes setopciones en mi script y descubrí set -uque parece ser perfecto para salir de mi script si una variable no se configura correctamente (por ejemplo, eliminar usuarios). De acuerdo con la página del manual , set -uy set -ehace lo siguiente ...

-e  Exit immediately if a command exits with a non-zero status.
-u  Treat unset variables as an error when substituting.

Creé un script de prueba para probar esta funcionalidad, pero no parece funcionar como se esperaba. ¿Quizás alguien podría explicarme mejor mi problema y dónde estoy interpretando mal? El script de prueba está abajo. Gracias.

set -e
set -u
testing="This works"
echo $?
echo ${testing}
testing2=
echo $?
echo ${testing2}
testing3="This should not appear"
echo $?
echo ${testing3}

Espero que el script muestre 0 y "Esto funciona" , y luego falla ya ${testing2}que no está configurado.

En su lugar, se muestra 0 y "Esto funciona" , siga 0 y luego 0 Esto no debería aparecer

¿Alguien puede proporcionar algún conocimiento? Gracias.

Azifor
fuente
1
Entonces, seguimiento ... ¿hay alguna manera de hacer que establecer una variable en la cadena nula sea ilegal / generar un error? Supongo que no.
Luke Davis

Respuestas:

10

De "man Bash":

Se establece un parámetro si se le ha asignado un valor. La cadena nula es un valor válido. Una vez que se establece una variable, puede desarmarse solo mediante el comando incorporado unset.

Cuando lo hace testing2=, está configurando la variable en la cadena nula.

Cambie eso unset testing2e intente nuevamente.


El set -eno ayuda en este caso ya que una asignación nunca tiene un código de salida de 1. Intente esto para ver que el último comando ejecutado (la asignación) tiene un código de salida de 0, o lea esta pregunta :

$ false; a=""; echo $?
0

Y también creo que el uso de set -e es más un problema que una solución.

Lo que puede obtener un error con el uso de variables no establecidas es set -u:

#!/bin/bash
set -u
testing="This works"
echo ${testing}
unset testing2
echo ${testing2}
testing3="This should not appear"
echo ${testing3}

Saldrá:

$  ./script.sh
This works
./script.sh: line 9: testing2: unbound variable
Comunidad
fuente
3

testing2=establece la testing2variable en una cadena vacía; la variable en realidad está establecida .

Sin embargo, si tuviera que ejecutar echo $testing99un shell Bash interactivo (sin configuración errexit, es decir, set -e), obtendría un error:

bash: testing99: unbound variable

Aparte

Mientras probaba los scripts en este momento, descubrí que un shell interactivo no siempre se cierra al intentar expandir una variable que no se ha establecido mientras que siempre sale un shell no interactivo (que ejecuta un script de shell) . De acuerdo con la página de manual de POSIX para :set

-u El shell debe escribir un mensaje de error estándar cuando intenta expandir una variable que no está establecida y salir inmediatamente. Un shell interactivo no debe salir.

Un Bash shell interactivo no saldrá a menos que errexittenga también ha establecido. Por otro lado, un shell de tablero interactivo no saldrá, incluso si set -ese ha ejecutado previamente.

Anthony Geoghegan
fuente
Si el guión no sale con set -e; set -u; desarmado aa; echo $ aa, entonces el guión está mal.
schily
@schily Cuando noté esto por primera vez, pensé que los autores del guión sabían mejor que yo y que podría haber habido cierta ambigüedad en las especificaciones POSIX pero que volví a revisar pubs.opengroup.org/onlinepubs/9699919799/utilities/… , I De acuerdo que parece un error, está bien.
Anthony Geoghegan
Hay una regla simple: cuando Korn Shell y Bourne Shell están de acuerdo y otra implementación de shell tiene una desviación, entonces el otro shell se comporta incorrectamente.
schily