Verifica se una variabile è impostata in bash quando si utilizza "set -o nounset"


95

Il codice seguente termina con un errore di variabile non associata. Come risolvere questo problema, usando ancora l' set -oopzione nounset?

#!/bin/bash

set -o nounset

if [ ! -z ${WHATEVER} ];
 then echo "yo"
fi

echo "whatever"

Risposte:


98
#!/bin/bash

set -o nounset


VALUE=${WHATEVER:-}

if [ ! -z ${VALUE} ];
 then echo "yo"
fi

echo "whatever"

In questo caso, VALUEfinisce per essere una stringa vuota se WHATEVERnon è impostata. Stiamo usando l' {parameter:-word}espansione, che puoi cercare in man bash"Parameter Expansion".


14
basta sostituire se [! -z $ {VALUE}]; con if [! -z $ {QUALUNQUE: -}];
Angelom

18
:-controlla se la variabile non è impostata o è vuota. Se si desidera controllare solo se è impostata, utilizzare -: VALUE=${WHATEVER-}. Inoltre, un modo più leggibile per verificare se una variabile è vuota:if [ "${WHATEVER+defined}" = defined ]; then echo defined; else echo undefined; fi
l0b0

1
Inoltre, questo non funzionerà se $WHATEVERcontiene solo spazi bianchi - Vedi la mia risposta.
l0b0

9
C'è un motivo per usare " ! -z" invece di " -n"?
Jonathan Hartley

31

Devi citare le variabili se vuoi ottenere il risultato che ti aspetti:

check() {
    if [ -n "${WHATEVER-}" ]
    then
        echo 'not empty'
    elif [ "${WHATEVER+defined}" = defined ]
    then
        echo 'empty but defined'
    else
        echo 'unset'
    fi
}

Test:

$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER='   '
$ check
not empty

Ho provato questo e mi sono sorpreso funziona questo ... tutto è corretto tranne che in base alle "info bash", "${WHATEVER-}"dovrebbe avere un ":"(due punti) prima della "-"(trattino) come: "${WHATEVER:-}"e "${WHATEVER+defined}"dovrebbe avere due punti prima che il "+"(più) come: "${WHATEVER:+defined}". Per me, funziona in entrambi i casi, con o senza il colon. Su alcune versioni di 'nix probabilmente non funzionerà senza includere i due punti, quindi probabilmente dovrebbe essere aggiunto.
Kevin Fegan

8
No, -, +, :+, e :-sono tutti supportati. Il primo rileva se la variabile è impostata e il secondo rileva se è impostata o vuota . Da man bash: "Omettendo i due punti si ottiene un test solo per un parametro non impostato".
l0b0

1
Non importa =). Hai ragione. Non so come mi sia perso.
Kevin Fegan

Dalla documentazione : In altre parole, se si includono i due punti, l'operatore verifica l'esistenza di entrambi i parametri e che il suo valore non sia nullo; se i due punti vengono omessi, l'operatore verifica solo l'esistenza.
Acumenus

8

Che ne dici di un oneliner?

[ -z "${VAR:-}" ] && echo "VAR is not set or is empty" || echo "VAR is set to $VAR"

-z controlla sia la variabile vuota che non impostata


2
No, -zcontrolla solo se il parametro successivo è vuoto. -zè solo un argomento del [comando. L'espansione variabile avviene prima che [ -zpossa fare qualsiasi cosa.
dolmen

1
Questa sembra la soluzione corretta, in quanto non genera un errore se $ VAR non è impostato. @dolmen puoi fornire un esempio di quando non funzionerebbe?
Chris Stryczynski

@dolmen avendo letto varie risorse di bash sull'espansione dei parametri e trovando le altre risposte troppo complicate, non vedo niente di sbagliato in questo. quindi il tuo "chiarimento", sebbene tecnicamente corretto, sembra piuttosto inutile in pratica, a meno che non sia necessario differenziare unset vs vuoto. Ho provato non impostato, vuoto e non vuoto, (bash 4) e praticamente ha fatto ciò che viene pubblicizzato ogni volta.
JL Peyret

8

Presupposti:

$ echo $SHELL
/bin/bash
$ /bin/bash --version | head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
$ set -o nounset

Se si desidera che uno script non interattivo stampi un errore ed esca se una variabile è nulla o non è impostata:

$ [[ "${HOME:?}" ]]

$ [[ "${IAMUNBOUND:?}" ]]
bash: IAMUNBOUND: parameter null or not set

$ IAMNULL=""
$ [[ "${IAMNULL:?}" ]]
bash: IAMNULL: parameter null or not set

Se non vuoi che lo script esca:

$ [[ "${HOME:-}" ]] || echo "Parameter null or not set."

$ [[ "${IAMUNBOUND:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

$ IAMNULL=""
$ [[ "${IAMUNNULL:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

Puoi anche usare [e ]invece di [[e ]]sopra, ma quest'ultimo è preferibile in Bash.

Nota cosa fa il colon sopra. Dai documenti :

In altre parole, se vengono inclusi i due punti, l'operatore verifica l'esistenza di entrambi i parametri e che il suo valore non sia nullo; se i due punti vengono omessi, l'operatore verifica solo l'esistenza.

Apparentemente non c'è bisogno di -no -z.

In sintesi, in genere posso solo usare [[ "${VAR:?}" ]]. Per gli esempi, questo stampa un errore ed esce se una variabile è nulla o non è impostata.


4

Puoi usare

if [[ ${WHATEVER:+$WHATEVER} ]]; then

ma

if [[ "${WHATEVER:+isset}" == "isset" ]]; then

potrebbe essere più leggibile.


I confronti di stringhe dovrebbero utilizzare l' =operatore standard (POSIX) , non ==per facilitare la portabilità e [invece di, [[se possibile.
Jens

2
@ Jens La domanda è specifica per bash e include set -o nounsetquale è specifica per bash. Se metti un #!/bin/bashall'inizio del tuo script, in realtà è meglio usare i miglioramenti di bash.
Bruno Bronosky

0

Anche se questo non è esattamente il caso d'uso richiesto sopra, ho scoperto che se vuoi usare nounset(o -u) il comportamento predefinito è quello che desideri: uscire da diverso da zero con un messaggio descrittivo.

Mi ci è voluto abbastanza tempo per rendermene conto che ho pensato che valesse la pena pubblicare come soluzione.

Se tutto ciò che vuoi è fare eco a qualcos'altro quando esci o fare un po 'di pulizia, puoi usare una trappola.

L' :-operatore è probabilmente quello che vuoi altrimenti.

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.