Utilizzo di unset e impostazione di una variabile vuota


108

Attualmente sto scrivendo un framework di test bash, in cui in una funzione di test è possibile utilizzare sia test bash standard ( [[) che matcher predefiniti. I matcher sono wrapper per '[[' e oltre a restituire un codice di ritorno, impostano un messaggio significativo che dice ciò che ci si aspettava.

Esempio:

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

            return 1
    fi
}

Quindi, quando viene utilizzato un matcher e fallisce, solo allora viene impostato un messaggio_errore.

Ora, a un certo punto dopo, provo se i test hanno avuto successo. Se è andato a buon fine, stampo l'aspettativa in verde, se è fallito in rosso.

Inoltre, potrebbe essere impostato un messaggio error_message, quindi provo se un messaggio esiste, lo stampo e quindi lo disattivi (perché il seguente test potrebbe non impostare un error_message):

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

    unset -v error_message
fi

Ora la mia domanda è, se è meglio annullare l'impostazione della variabile o semplicemente impostarla su "", come

error_message=''

Qual è il migliore? Fa davvero la differenza? O forse dovrei avere un flag aggiuntivo che indica che il messaggio è stato impostato?


1
Se non ti confronti error_messagecon nient'altro, direi che non importa. Tuttavia, penso che tu voglia [[ $error_message ]], altrimenti stai testando l'esistenza della stringa letterale "messaggio_errore".
chepner

@chepner Sì, è stato un errore di battitura. Aggiustato.
helpermethod

Risposte:


143

Per lo più non vedi una differenza, a meno che tu non stia 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

Quindi, in realtà, dipende da come testerai la variabile.

Aggiungerò che il mio modo preferito di testare se impostato è:

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

o

[[ -z $var ]]  # True if zero length

43
var=non è "non impostato". È solo una stringa vuota non quotata. Inoltre set -u, le varie forme di espansione dei parametri di bash possono anche distinguere tra valori non impostati e valori nulli: si ${foo:bar}espande in "bar" quando foonon è impostato, ma "" quando fooè nullo, mentre si ${foo:-bar}espande in "bar" se pippo è non impostato o nullo.
chepner

1
[[ -n $var ]]è falso se varè impostato su una stringa vuota.
chepner

1
se usi 'declare -p' per controllare la variabile 'esistenza' allora var = mostrerà 'declare - var = ""' devi usare unset per sbarazzartene, ovviamente se è una variabile di sola lettura allora non puoi ottenere sbarazzarsene ovviamente. Inoltre, se var = qualcosa all'interno di una funzione, non dovrai preoccuparti di sbarazzartene se usi "local var = value" fai attenzione però, perché "declare var = value" è anche locale. Nel caso di declare devi impostarlo esplicitamente come globale usando "declare -g var = value", senza dichiararlo devi impostarlo esplicitamente come locale usando "local". Le variabili globali vengono solo cancellate / w unset.
osirisgothra

@osirisgothra: buon punto sulle variabili locali. Ovviamente in genere è meglio dichiarare (o localizzare) tutte le variabili in una funzione in modo che sia incapsulata.
cdarke

3
@chepner dovrebbe essere ${foo-bar}invece di ${foo:bar}. prova tu stesso:unset a; echo ">${a:-foo}-${a:foo}-${a-foo}<"
Liviu Chircu

17

Come è stato detto, l'uso di unset è diverso anche con gli array

$ foo=(4 5 6)

$ foo[2]=

$ echo ${#foo[*]}
3

$ unset foo[2]

$ echo ${#foo[*]}
2

2

Quindi, annullando l'impostazione dell'indice 2 dell'array, essenzialmente rimuovi quell'elemento nell'array e diminuisci la dimensione dell'array (?).

Ho fatto il mio test ..

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

Il che si traduce in ..

3
0

Quindi, solo per chiarire che il disinserimento dell'intero array lo rimuoverà completamente.


0

Sulla base dei commenti sopra, ecco un semplice test:

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

Esempio:

$ 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.