Inicializar variables de Bash: ¿es necesario, recomendado o definido a medida que avanza?

9

¿Hay alguna ventaja / desventaja de inicializar el valor de una variable bash en el script, ya sea antes del código principal o variables locales en una función antes de asignarle el valor real?

¿Necesito hacer algo como esto:

init()
{
    name=""
    name=$1
}

init "Mark"

¿Existe algún riesgo de que las variables se inicialicen con valores basura (si no se inicializan) y que tengan un efecto negativo en los valores de las variables?

Ciro
fuente
2
¿De dónde sacaste esta idea?
66
@DoritoStyle Bueno, si uno está acostumbrado a lenguajes de nivel inferior, como C, entonces esto es algo perfectamente válido de qué preocuparse.
Kusalananda
@Kusalananda ¿No es el equivalente C de ese código name = ""; name = argv[1];? ¿Y no es eso tan inútil?
Joseph Sible: reinstala a Mónica el
1
@ JosephSible-ReinstateMonica Sí. El código C que publicaste no tiene sentido. Sin embargo, en C, a diferencia de en el shell, las variables no inicializadas no tienen un valor particular bien definido. Esto significa que inicializar variables en lenguajes como C tiene sentido en muchas circunstancias. No es necesario hacerlo en el shell. Inicializar una variable en C solo para establecerla inmediatamente en otro valor no tiene sentido, como usted señala.
Kusalananda

Respuestas:

22

No es beneficioso asignar una cadena vacía a una variable y luego asignarle inmediatamente otra cadena variable. Una asignación de un valor a una variable de shell sobrescribirá por completo su valor anterior.

Que yo sepa, no hay ninguna recomendación que diga que debe inicializar explícitamente las variables en cadenas vacías. De hecho, hacerlo puede enmascarar errores en algunas circunstancias (errores que de otro modo serían evidentes si se ejecutan bajo set -u, ver más abajo).

Una variable no establecida, que no se utiliza desde el inicio de un script o que se desarma explícitamente al ejecutar el unsetcomando en ella, no tendrá valor. El valor de tal variable será nada. Si se usa como "$myvariable", obtendrá el equivalente de "", y nunca obtendrá "datos basura".

Si la opción de shell nounsetse establece con uno set -o nounseto set -u, entonces hacer referencia a una variable no establecida hará que el shell produzca un error (y un shell no interactivo terminaría):

$ set -u
$ echo "$myvariable"
/bin/sh: myvariable: parameter not set

o en bash:

$ set -u
$ echo "$myvariable"
bash: myvariable: unbound variable

Las variables de shell serán inicializadas por el entorno si el nombre de la variable corresponde a una variable de entorno existente.

Si espera que esté utilizando una variable que puede ser inicializada por el entorno de esta manera (y si no es deseada), puede desarmarla explícitamente antes de la parte principal de su script:

unset myvariable    # unset so that it doesn't inherit a value from the environment

lo que también lo eliminaría como una variable de entorno, o simplemente puede ignorar su valor inicial y simplemente sobrescribirlo con una asignación (lo que haría que la variable de entorno cambie también el valor).

Nunca encontraría basura no inicializada en una variable de shell (a menos que, como se indicó, esa basura ya existiera en una variable de entorno con el mismo nombre).

Kusalananda
fuente
3
Si bien no hay ningún valor a establecer una variable a un valor vacío y luego inmediatamente la configuración como la OP literalmente hace, existe un valor en el establecimiento de un valor vacío (o unsetting) antes de ejecutar algún tipo de foro whilebucle para establecer en un calculado valor si hay alguna posibilidad de que el bucle no se ejecute realmente debido a que no se cumplen las condiciones; y la variable podría haberse establecido en algún otro valor en el entorno que el script heredó. Pero podría decirse que es mejor poner todo en main()ay definir las variables como local.
Monty Harder
También puede detectar variables no establecidas utilizando los operadores de expansión de parámetros, omitiendo :, por ejemplo${myvariable-defaultvalue}
Barmar
3

Editar : Vaya, aparentemente la declaración es diferente de la inicialización. Lo dejaré aquí de todos modos para que los programadores novatos como yo puedan aprender de mi error.


La ventaja de declarar variables locales en una función es que puede copiar fácilmente el código.

Por ejemplo, digamos que tengo una función:

foo(){
    local name
    name="$1"
    echo "$name"
}

Si quiero convertirlo en un script, simplemente ignoro la localdeclaración y copio todo lo demás:

#!/bin/bash
name="$1"
echo "$name"

Si la declaración y la asignación estuvieran en la misma línea, tendría que editar manualmente la localparte antes de poder convertirla en un script:

foo(){
    local name="$1"
    echo "$name"
}

En este ejemplo, no es un gran problema, pero si se trata de funciones más grandes y complejas, puede ser más doloroso.

wjandrea
fuente
1
La pregunta no era sobre combinar la declaración y la inicialización. Se trataba de inicializar con un valor vacío antes de asignar un valor real.
Barmar
@Barmar Oh, acabo de buscar "inicialización". Pensé que era sinónimo de "declaración" ...
wjandrea