¿Hay algún daño en el uso de variables que no están configuradas?

¿Hay algún daño en el uso de variables que no están configuradas?

Digamos que tengo el siguiente código:

# Check if the color prompt is enabled and supported on this system
if [ -n "$force_color_prompt" ] && [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
    GREEN="\033[1;32m"
    DIM="\033[2m"
    RESET="\033[00m"
fi

echo -e "Oh, ${GREEN}green${RESET} world, ${DIM}don't desert me now...${RESET}"

Si la compatibilidad con el color está habilitada, se reproducirá una bonita línea de color. Si la compatibilidad con colores no está habilitada, no se habrán configurado valores como ${GREEN}y el texto se imprimirá en el color blanco habitual con fondo negro.

El código se basa en el hecho de que las variables que no están configuradas simplemente se evaluarán como una cadena vacía (lo cual, en mis pruebas, sí lo hacen). ¿Esto causará errores o problemas en algunos sistemas, o todas las variables inexistentes?siempreevaluar a una cadena vacía? ¿Hay alguna razón por la que no debería confiar en este mecánico?

Respuesta1

Las variables inexistentes siempre se evaluarán como una cadena vacía cuando se expandan como $FOOor (equivalentemente) ${FOO}, y no hay ningún daño en depender de eso, excepto en un caso particular:

Si alguien llamó set -ual shell actual antes de intentar usar esa variable, ha habilitado esta configuración:

              -u Trata las variables no configuradas como un error al realizar parámetros.
                      expansión del éter. Si se intenta la expansión en un desarmado
                      variable, el shell imprime un mensaje de error y, si no
                      interactivo, sale con un estado distinto de cero.

Esto significa que si estás escribiendo una función que está diseñada para ser incluida en un script que otra persona tiene control, es posible que tengas que estar paranoico respecto al uso de variables no configuradas; de lo contrario, si las usaron set -uantes de llamar a tu función, su script saldría con un mensaje de error la primera vez que intentara expandir una variable no configurada.

Si está escribiendo su propio script, no hay nada de malo en contar con variables no configuradas que se expandan a la cadena vacía.

EDITAR- Además, solo una idea: dado que está condicionando todo a si las capacidades de color de terminfo están disponibles para su terminal, ¿por qué no usar terminfo para generar las secuencias, en lugar de codificar los valores vt100? Algo como:

if [ -n "$force_color_prompt" ] && type tput &>/dev/null; then
    GREEN="$(tput setaf 2)$(tput bold)"
    DIM="$(tput dim)"
    RESET="$(tput sgr0)"
fi

Esto puede brindarle cierta portabilidad a través de otras terminales (aunque, hay que admitirlo, la cantidad de terminales que no usan los códigos que mostró es pequeña y cada vez menor). También puede perder algo de portabilidad, ya que es posible que algunas capacidades no existan en algunas plataformas dependiendo de qué tan correctas sean las definiciones de terminfo. YMMV.

Respuesta2

Una de las características más exclusivas del lenguaje de scripting de shell compatible con POSIX esexpansión de parámetros. Se puede utilizar de diversas formas para realizar tareas que no suelen estar asociadas con valores variables. En el shell, una variable tiene el potencial de ser más que un simple valor: puede ser un elemento procesable. Tiene el potencial de ponerse a prueba. Y esto viene explícitamente, sin necesidad de configurar opciones de shell.

Por ejemplo, su código podría verse así:

N= ERR='error encountered - exiting' 
: ${force_color_prompt?"$ERR"}
/usr/bin/tput setaf >/dev/null 2>&1 || ${N:?"$ERR"}
: "${GREEN:=\033[1;32m}" "${DIM:=\033[2m}" "${RESET:=\033[00m}"
printf %b\\n \
    "Oh, ${GREEN}green${RESET} world, ${DIM}don't desert me now...${RESET}"

La $Nvariable se establece explícitamente en la cadena nula, por lo que cuando se evalúa con la ${N:?}forma de expansión de parámetros, se sale automáticamente de su shell principal y ?también se evalúa la expansión de la siguiente declaración, cuyos resultados se muestran en stderr. Lo mismo ocurre $force_color_prompt: si no está configurado, el script sale con un error y genera $ERRtodo stderrautomáticamente.

Los $GREEN $RESETy $DIMse establecen en los valores que usted definió si actualmente no están configurados o si están configurados en la ''cadena nula. Esto le permite pasar sus valores al script como variables de entorno. Por ejemplo, si el fragmento anterior estuviera en un script llamado greenworld.shy lo llamé así:

GREEN="$(tput setaf 2)$(tput bold)" greenworld.sh

Entonces $GREENno se restablecería en el contenido del script y, en cambio, heredaría el valor explícito que le establecí. Esto hace que los scripts de shell sean flexibles.

Y usarlo tputde esa manera, como ha recomendado godlygeek, es una recomendación, por un segundo.

En el shell, una variable no configurada a veces puede ser tan útil como una configurada. Aquí hay un ejemplo diferente:

set -- * 
while ${1+:} false ; do
    #do stuff until all positionals are shifted away
shift ; done

En ese ejemplo, siempre que el primer parámetro esté definido, se expandirá al :valor nulo incorporado del shell, lo que en consecuencia hará que la siguiente falseinvocación sea no operativa. Pero una vez que se han shifteliminado todos los parámetros posicionales ${1}, no se expande de esa manera, falsese invoca y el whileciclo finaliza. Puedes hacer innumerables variaciones sobre esto.

Respuesta3

En uso normal, es decir, cuando simplemente estás expandiendo variables, una variable no configurada se trata como vacía en todos los shells estilo Bourne/POSIX. La excepción es cuando set -o unsetaka set -uestá vigente, en cuyo caso el shell generará un error si intenta acceder al valor de una variable no configurada (consulteLa respuesta de Godlygeek).

Hay formas de comprobar si una variable no está configurada o está vacía; por ejemplo, la construcción ${foo-bar}se expande al valor de foosi está configurada (incluso si está vacía) y barsi foono está configurada;
${foo:-bar}(con dos puntos adicionales) trata una variable vacía como si no estuviera configurada. Otras construcciones de expansión similares ${foo+bar}, ${foo?bar}, ${foo=bar}se comportan de manera similar. También aparecerá una variable vacía en la salida de sety export(si se exporta), entre otras diferencias. Sólo te encontrarás con estas diferencias si así lo deseas.

Sin embargo, hay una razón diferente parasiempre inicializar variables: ¿Cómo sabes que la variable realmente no está configurada? Es posible que la persona que llama haya definido una variable similar para sus propios fines. Si la persona que llama es otra parte del mismo script, entonces su uso en una función sobrescribirá la de la persona que llama, a menos que declare la variable como local (lo cual solo es posible en ksh/bash/zsh), por lo que los conflictos de nombres de variables son un problema. de todos modos. Pero también puede suceder que la variable esté presente en el entorno, porque alguien más eligió el mismo nombre de variable que usted. Existe una especie de convención para usar nombres en minúsculas para las variables del shell y nombres en mayúsculas para las variables de entorno, pero no resuelve todos los conflictos y no se sigue universalmente.

$ exportar DIM=1 SUM=42
$ fiesta
Oh, mundo verde, no me abandones ahora...

información relacionada