Usar desarmar frente a establecer una variable en vacío

108

Actualmente estoy escribiendo un marco de prueba de bash, donde en una función de prueba, [[se pueden usar tanto las pruebas de bash estándar ( ) como los matchers predefinidos. Los comparadores son envoltorios de '[[' y, además de devolver un código de retorno, establecen un mensaje significativo que diga lo que se esperaba.

Ejemplo:

string_equals() {
    if [[ ! $1 = $2 ]]; then
            error_message="Expected '$1' to be '$2'."

            return 1
    fi
}

Entonces, cuando se usa un comparador y falla, solo entonces se establece un error_message.

Ahora, en algún momento después, pruebo si las pruebas tuvieron éxito. Si tuvo éxito, imprimo la expectativa en verde, si falló en rojo.

Además, puede haber un error_message configurado, así que pruebo si existe un mensaje, lo imprimo y luego lo desarmo (porque la siguiente prueba puede no establecer un error_message):

if [[ $error_message ]]; then
    printf '%s\n' "$error_message"

    unset -v error_message
fi

Ahora mi pregunta es, si es mejor desarmar la variable, o simplemente establecerla en '', como

error_message=''

¿Cuál es mejor? ¿Realmente hace alguna diferencia? ¿O tal vez debería tener una bandera adicional que indique que el mensaje se estableció?

método de ayuda
fuente
1
Si nunca se compara error_messagecon nada más, diría que no importa. Sin embargo, creo que lo desea [[ $error_message ]], de lo contrario, está probando que existe la cadena literal "mensaje_error".
chepner
@chepner Sí, fue un error tipográfico. Arreglado.
helpermethod

Respuestas:

143

En general, no ve una diferencia, a menos que esté usando set -u:

/home/user1> var=""
/home/user1> echo $var

/home/user1> set -u
/home/user1> echo $var

/home/user1> unset var
/home/user1> echo $var
-bash: var: unbound variable

Entonces, realmente, depende de cómo vas a probar la variable.

Agregaré que mi forma preferida de probar si está configurada es:

[[ -n $var ]]  # True if the length of $var is non-zero

o

[[ -z $var ]]  # True if zero length
cdarke
fuente
43
var=no está "no configurado". Es solo una cadena vacía sin comillas. Además set -u, las diversas formas de expansión de parámetros de bash también pueden distinguir entre valores nulos y no definidos: se ${foo:bar}expande a "bar" cuando no fooestá configurado, pero "" cuando fooes nulo, mientras que se ${foo:-bar}expande a "bar" si foo no está configurado o es nulo.
chepner
1
[[ -n $var ]] es falso si var se establece en la cadena vacía.
Chepner
1
si usa 'declare -p' para verificar la variable 'existencia', entonces var = mostrará 'declare - var = ""' debe usar unset para deshacerse de él, por supuesto, si es una variable de solo lectura, entonces no puede obtener deshacerse de él, por supuesto. Además, si var = algo dentro de una función, no tendrá que preocuparse por deshacerse de él si usa "local var = value", pero tenga cuidado, porque "declare var = value" también es local. En el caso de declare tienes que configurarlo explícitamente como global usando "declare -g var = value", sin declarar tienes que configurarlo explícitamente como local usando "local". Las vars globales solo se borran / w no configuradas.
osirisgothra
@osirisgothra: buen punto sobre las variables locales. Por supuesto, generalmente es mejor declarar (o localizar) todas las variables en una función para que esté encapsulada.
cdarke
3
@chepner debería ser en ${foo-bar}lugar de ${foo:bar}. prueba por ti mismo:unset a; echo ">${a:-foo}-${a:foo}-${a-foo}<"
Liviu Chircu
17

Como se ha dicho, el uso de unset también es diferente con las matrices

$ foo=(4 5 6)

$ foo[2]=

$ echo ${#foo[*]}
3

$ unset foo[2]

$ echo ${#foo[*]}
2
Steven Penny
fuente
2

Entonces, al desarmar el índice 2 de la matriz, esencialmente elimina ese elemento en la matriz y disminuye el tamaño de la matriz (?).

Hice mi propia prueba ..

foo=(5 6 8)
echo ${#foo[*]}
unset foo
echo ${#foo[*]}

Lo que resulta en..

3
0

Entonces, solo para aclarar que desarmar toda la matriz, de hecho, la eliminará por completo.

PdC
fuente
0

Basado en los comentarios anteriores, aquí hay una prueba simple:

isunset() { [[ "${!1}" != 'x' ]] && [[ "${!1-x}" == 'x' ]] && echo 1; }
isset()   { [ -z "$(isunset "$1")" ] && echo 1; }

Ejemplo:

$ unset foo; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's unset
$ foo=     ; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's set
$ foo=bar  ; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's set
Jonathan H
fuente