Come determinare se una variabile bash è vuota?


Risposte:


1053

Ciò restituirà true se una variabile non è impostata o è impostata sulla stringa vuota ("").

if [ -z "$VAR" ];

14
Ciò include se una variabile È impostata su un valore ""?
Brent,

11
Sì, lo fa ... "-z" testa una stringa di lunghezza zero.
David Z,

91
if [ ! -z "$VAR" ];
Aaron Copley,

263
l'inverso di -zè-n if [ -n "$VAR" ];
Felipe Alvarez,

19
Le doppie virgolette assicurano che la variabile non venga divisa. Un semplice $varsu una riga di comando verrà diviso per il suo spazio in un elenco di parametri, mentre "$var"sarà sempre solo un parametro. Citando le variabili spesso è una buona pratica e ti impedisce di inciampare su nomi di file contenenti spazi bianchi (tra le altre cose). Esempio: dopo averlo fatto a="x --help", prova cat $a- ti darà la pagina di aiuto per cat. Quindi prova cat "$a"- lo dirà (di solito) cat: x --help: No such file or directory. In breve, cita presto e cita spesso e non te ne pentirai quasi mai.
Score_Under

247

In Bash, quando non sei interessato alla portabilità verso shell che non la supportano, dovresti sempre usare la sintassi a doppia parentesi:

Uno dei seguenti:

if [[ -z $variable ]]
if [[ -z "$variable" ]]
if [[ ! $variable ]]
if [[ ! "$variable" ]]

In Bash, usando parentesi quadre doppie, le virgolette non sono necessarie. È possibile semplificare il test per una variabile che fa contenere un valore di:

if [[ $variable ]]

Questa sintassi è compatibile con ksh (almeno ksh93, comunque). Non funziona con POSIX pure o con vecchie shell Bourne come sh o dash.

Vedi la mia risposta qui e BashFAQ / 031 per ulteriori informazioni sulle differenze tra parentesi quadre doppie e singole.

Puoi verificare se una variabile non è specificatamente impostata (come distinta da una stringa vuota):

if [[ -z ${variable+x} ]]

dove la "x" è arbitraria.

Se vuoi sapere se una variabile è nulla ma non è impostata:

if [[ -z $variable && ${variable+x} ]]

1
Per if [[ $variable ]]me ha funzionato bene e non ha nemmeno bisogno di set -uquello richiesto da una delle altre soluzioni proposte.
Teemu Leisti,

3
Penso che sia meglio della risposta accettata.
Q

2
Perché stai raccomandando una funzione non portatile quando ciò non dà alcun vantaggio?
Alastair Irvine,

19
@AlastairIrvine: menziono la portabilità nella prima frase della mia risposta, il titolo e il corpo della domanda contengono la parola "Bash" e la domanda è taggata bash , e la struttura a doppia parentesi offre chiari vantaggi in molti modi. E non consiglio di mescolare gli stili di parentesi per motivi di coerenza e manutenibilità. Se hai bisogno della massima portabilità del minimo comune denominatore, usa al shposto di Bash. Se hai bisogno delle maggiori capacità che offre, usa Bash e usalo completamente.
Dennis Williamson,

2
@BrunoBronosky: ho ripristinato la modifica. Non è necessario per ;alla fine. Il thenpuò essere sulla riga successiva senza punto e virgola.
Dennis Williamson,

230

Una variabile in bash (e qualsiasi shell compatibile con POSIX) può trovarsi in uno dei tre stati:

  • non settato
  • impostato sulla stringa vuota
  • impostato su una stringa non vuota

Il più delle volte devi solo sapere se una variabile è impostata su una stringa non vuota, ma a volte è importante distinguere tra non impostato e impostato su una stringa vuota.

I seguenti sono esempi di come è possibile testare le varie possibilità e funziona con bash o con qualsiasi shell compatibile con POSIX:

if [ -z "${VAR}" ]; then
    echo "VAR is unset or set to the empty string"
fi
if [ -z "${VAR+set}" ]; then
    echo "VAR is unset"
fi
if [ -z "${VAR-unset}" ]; then
    echo "VAR is set to the empty string"
fi
if [ -n "${VAR}" ]; then
    echo "VAR is set to a non-empty string"
fi
if [ -n "${VAR+set}" ]; then
    echo "VAR is set, possibly to the empty string"
fi
if [ -n "${VAR-unset}" ]; then
    echo "VAR is either unset or set to a non-empty string"
fi

Ecco la stessa cosa ma in una comoda tabella:

                        +-------+-------+-----------+
                VAR is: | unset | empty | non-empty |
+-----------------------+-------+-------+-----------+
| [ -z "${VAR}" ]       | true  | true  | false     |
| [ -z "${VAR+set}" ]   | true  | false | false     |
| [ -z "${VAR-unset}" ] | false | true  | false     |
| [ -n "${VAR}" ]       | false | false | true      |
| [ -n "${VAR+set}" ]   | false | true  | true      |
| [ -n "${VAR-unset}" ] | true  | false | true      |
+-----------------------+-------+-------+-----------+

Il ${VAR+foo}costrutto si espande nella stringa vuota se VARnon è impostato o foose VARè impostato su qualcosa (inclusa la stringa vuota).

Il ${VAR-foo}costrutto si espande al valore di VARif impostato (incluso set su stringa vuota) e foose non impostato. Ciò è utile per fornire valori predefiniti sostituibili dall'utente (ad esempio, ${COLOR-red}dice di usare a redmeno che la variabile non COLORsia stata impostata su qualcosa).

Il motivo per cui [ x"${VAR}" = x ]è spesso consigliato per verificare se una variabile non è impostata o è impostata su una stringa vuota è perché alcune implementazioni del [comando (note anche come test) sono errate. Se VARè impostato su qualcosa di simile -n, alcune implementazioni faranno la cosa sbagliata quando vengono fornite [ "${VAR}" = "" ]perché il primo argomento a [viene erroneamente interpretato come l' -noperatore, non una stringa.


3
Il test per una variabile impostata su una stringa vuota può anche essere fatto usando [ -z "${VAR-set}" ].
nwellnhof,

@nwellnhof: grazie! Ho aggiornato la mia risposta per utilizzare la sintassi più breve.
Richard Hansen

Qual è la differenza tra il primo e l'ultimo costrutto? Entrambi corrispondono a "VAR non è impostato o è impostato su una stringa non vuota".
Faheem Mitha,

1
@FaheemMitha: non è colpa tua - la mia risposta è stata difficile da leggere. Ho aggiunto un tavolo per rendere la risposta più chiara.
Richard Hansen,

2
I controlli non impostati non sono affidabili. Se l'utente ha chiamato set -uo set -o nounsetin bash, il test provocherà solo l'errore "bash: VAR: variabile non associata". Consultare stackoverflow.com/a/13864829 per un controllo unset più affidabile. Il mio go-to controlla se una variabile è nulla o non impostata [ -z "${VAR:-}" ]. Il mio controllo per verificare se una variabile non è vuota è [ "${VAR:-}" ].
Kevin Jin,

38

-z è il modo migliore.

Un'altra opzione che ho usato è impostare una variabile, ma può essere sostituita da un'altra variabile, ad es

export PORT=${MY_PORT:-5432}

Se la $MY_PORTvariabile è vuota, allora PORTviene impostato a 5432, altrimenti PORT viene impostato al valore di MY_PORT. Nota che la sintassi include i due punti e il trattino.


L'ho trovato per caso oggi, ed era esattamente quello che volevo. Grazie! Devo tollerare set -o nounsetin alcuni script.
opello,

24

Se sei interessato a distinguere i casi di set-empty rispetto a unset set, guarda l'opzione -u per bash:

$ set -u
$ echo $BAR
bash: BAR: unbound variable
$ [ -z "$BAR" ] && echo true
bash: BAR: unbound variable
$ BAR=""
$ echo $BAR

$ [ -z "$BAR" ] && echo true
true

8

Un supplente che ho visto [ -z "$foo" ]è il seguente, tuttavia non sono sicuro del motivo per cui le persone usano questo metodo, qualcuno lo sa?

[ "x${foo}" = "x" ]

Ad ogni modo, se non si accettano variabili non impostate (da set -uo set -o nounset), si verificheranno problemi con entrambi questi metodi. C'è una soluzione semplice a questo:

[ -z "${foo:-}" ]

Nota: questo lascerà la tua variabile indefinita.


3
C'è un commento sull'alternativa -za pubs.opengroup.org/onlinepubs/009695399/utilities/test.html . Fondamentalmente, non è pensato per essere un'alternativa a -z. Piuttosto, gestisce i casi in cui $foopotrebbe espandersi a qualcosa che inizia con un metacarattere che [o testsarebbe stato confuso da. Mettere un non metacarattere arbitrario all'inizio elimina questa possibilità.
James Sneeringer,

6

La domanda chiede come verificare se una variabile è una stringa vuota e per questo sono già state fornite le risposte migliori.
Ma sono arrivato qui dopo un periodo trascorso programmando in php e quello che stavo effettivamente cercando era un controllo come la funzione vuota in php che funziona in una shell bash.
Dopo aver letto le risposte mi sono reso conto che non stavo pensando correttamente in bash, ma comunque in quel momento una funzione come vuota in php sarebbe stata davvero utile nel mio codice bash.
Dato che penso che ciò possa accadere ad altri, ho deciso di convertire la funzione php empty in bash

Secondo il manuale di php :
una variabile è considerata vuota se non esiste o se il suo valore è uno dei seguenti:

  • "" (una stringa vuota)
  • 0 (0 come numero intero)
  • 0.0 (0 come float)
  • "0" (0 come stringa)
  • un array vuoto
  • una variabile dichiarata, ma senza un valore

Naturalmente i casi null e false non possono essere convertiti in bash, quindi vengono omessi.

function empty
{
    local var="$1"

    # Return true if:
    # 1.    var is a null string ("" as empty string)
    # 2.    a non set variable is passed
    # 3.    a declared variable or array but without a value is passed
    # 4.    an empty array is passed
    if test -z "$var"
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is zero (0 as an integer or "0" as a string)
    elif [ "$var" == 0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is 0.0 (0 as a float)
    elif [ "$var" == 0.0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return
    fi

    [[ $( echo "" ) ]]
}



Esempio di utilizzo:

if empty "${var}"
    then
        echo "empty"
    else
        echo "not empty"
fi



Demo:
il seguente frammento:

#!/bin/bash

vars=(
    ""
    0
    0.0
    "0"
    1
    "string"
    " "
)

for (( i=0; i<${#vars[@]}; i++ ))
do
    var="${vars[$i]}"

    if empty "${var}"
        then
            what="empty"
        else
            what="not empty"
    fi
    echo "VAR \"$var\" is $what"
done

exit

uscite:

VAR "" is empty
VAR "0" is empty
VAR "0.0" is empty
VAR "0" is empty
VAR "1" is not empty
VAR "string" is not empty
VAR " " is not empty

Detto che in una logica bash i controlli su zero in questa funzione possono causare problemi collaterali, chiunque usi questa funzione dovrebbe valutare questo rischio e forse decidere di tagliare quei controlli lasciando solo il primo.


All'interno della funzione empty: perché hai scritto [[ $( echo "1" ) ]] ; returninvece che semplicemente return 1?
Dor,

5

l'intero if-then e -z non sono necessari.

["$ foo"] && echo "foo non è vuoto"
["$ foo"] || echo "foo è davvero vuoto"

3
Ciò fallirà se foo contiene solo spazi
Brian,

2
Fallirà anche in alcune shell se foo inizia con un trattino poiché viene interpretato come un'opzione. Ad esempio, su solaris ksh , zsh e bash non sono un problema, sh e / bin / test falliranno
ktf

4

Questo è vero esattamente quando $ FOO è impostato e vuoto:

[ "${FOO+x}" = x ] && [ -z "$FOO" ]

4

Personalmente preferisco un modo più chiaro per verificare:

if [ "${VARIABLE}" == "" ]; then
  echo VARIABLE is empty
else
  echo VARIABLE is not empty
fi

1
Alcune shell non accettano il doppio segno di uguale.
Dennis Williamson,

1
La domanda riguardava bash. Sto usando bash. Funziona bene per me. Di cosa stai parlando esattamente?
Fedir RYKHTIK,

2
Se stai usando Bash, dovresti usare parentesi quadre doppie. Il mio commento precedente era una semplice affermazione di fatto per coloro che potevano leggere la tua risposta e usare una shell diversa.
Dennis Williamson,

le parentesi quadre singole vanno bene in questo caso, consultare serverfault.com/questions/52034/…
Luca Borrione


4

I miei 5 centesimi: c'è anche una sintassi più breve di if ..., questa:

VALUE="${1?"Usage: $0 value"}"

Questa riga imposterà VALUE se è stato fornito un argomento e stamperà un messaggio di errore anteposto al numero della riga dello script in caso di errore (e terminerà l'esecuzione dello script).

Un altro esempio può essere trovato nella guida abs (cercare «Esempio 10-7»).


0

Non è una risposta esatta, ma ho incontrato questo trucco. Se la stringa che stai cercando proviene da "un comando", puoi effettivamente memorizzare il comando in un env. e quindi eseguirlo ogni volta per l'istruzione if, quindi non sono necessarie parentesi!

Ad esempio questo comando, che determina se sei su debian:

grep debian /proc/version

esempio completo:

IS_DEBIAN="grep -i debian /proc/version"

if $IS_DEBIAN; then
  echo 'yes debian'
else
  echo 'non debian'
fi

Quindi questo è come un modo indiretto (rieseguendolo ogni volta) per verificare la presenza di una stringa vuota (sembra che stia verificando la risposta di errore dal comando, ma capita anche di restituire una stringa vuota).

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.