Domanda

Se voglio verificare la stringa nulla lo farei

[ -z $mystr ]

ma cosa succede se voglio verificare se la variabile è stata definita affatto? O non c'è distinzione negli script bash?

È stato utile?

Soluzione

Penso che la risposta che stai cercando sia implicita (se non dichiarata) da Vinko 's rispondi , sebbene non sia spiegato semplicemente. Per distinguere se VAR è impostato ma vuoto o no, puoi usare:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Probabilmente puoi combinare i due test sulla seconda riga in uno con:

if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Tuttavia, se leggi la documentazione per Autoconf, scoprirai che non raccomandano di combinare i termini con '-a' e raccomandano di usare test semplici separati combinati con &&. Non ho riscontrato un sistema in cui si è verificato un problema; ciò non significa che non esistessero (ma probabilmente sono estremamente rari in questi giorni, anche se non erano così rari in un lontano passato).

Puoi trovare i dettagli di questi e altri relativi espansioni dei parametri della shell , test o < => comando e espressioni condizionali nel manuale di Bash.


Di recente mi è stato chiesto via e-mail di questa risposta con la domanda:

  

Usi due test e capisco bene il secondo, ma non il primo. Più precisamente non capisco la necessità di un'espansione variabile

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
     

Questo non compirebbe lo stesso?

if [ -z "${VAR}" ]; then echo VAR is not set at all; fi

Domanda corretta: la risposta è "No, la tua alternativa più semplice non fa la stessa cosa".

Supponi di scriverlo prima del tuo test:

VAR=

Il tuo test dirà " VAR non è impostato affatto " ;, ma il mio dirà (implicitamente perché non riecheggia nulla) " VAR è impostato ma il suo valore potrebbe essere vuoto & ;. quot Prova questo script:

(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:1 VAR is not set at all; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:2 VAR is not set at all; fi
)

L'output è:

JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all

Nella seconda coppia di test, la variabile è impostata, ma è impostata sul valore vuoto. Questa è la distinzione che fanno le notazioni [ e ${VAR=value}. Idem per ${VAR:=value} e ${VAR-value} e ${VAR:-value} e ${VAR+value} e così via.


Come Gili sottolinea nel suo risposta , se si esegue ${VAR:+value} con l'opzione bash, la risposta di base sopra non riesce con set -o nounset. È facilmente risolto:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Oppure potresti annullare l'opzione unbound variable con set +u (set -u è equivalente a <=>).

Altri suggerimenti

~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~> 

-z funziona anche per variabili non definite. Per distinguere tra un indefinito e uno definito useresti le cose elencate qui o, con spiegazioni più chiare , qui .

Il modo più pulito sta usando l'espansione come in questi esempi. Per ottenere tutte le opzioni, consultare la sezione Espansione dei parametri del manuale.

Parola alternativa:

~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED

Valore predefinito:

~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED

Ovviamente useresti uno di questi in modo diverso, mettendo il valore desiderato invece di "valore predefinito" e usando direttamente l'espansione, se appropriato.

Guida di scripting bash avanzata, 10.2. Sostituzione parametri:

  • $ {var + blahblah}: se var è definito, "blahblah" è sostituito dal espressione, altrimenti null viene sostituito
  • $ {var-blahblah}: se var è definito, viene esso stesso sostituito, altrimenti "blahblah" è sostituito
  • $ {var? blahblah}: se var è definito, viene sostituito, altrimenti il esiste una funzione con "blahblah" come messaggio di errore.

per basare la logica del programma sul fatto che la variabile $ mystr sia definita o meno, è possibile effettuare le seguenti operazioni:

isdefined=0
${mystr+ export isdefined=1}

ora, se isdefined = 0 la variabile non era definita, se isdefined = 1 la variabile era definita

Questo modo di controllare le variabili è migliore della risposta di cui sopra perché è più elegante, leggibile e se la shell bash è stata configurata per errori sull'uso di variabili non definite (set -u), lo script terminerà prematuramente.

Altre cose utili:

avere un valore predefinito di 7 assegnato a $ mystr se non definito, e lasciarlo intatto altrimenti:

mystr=${mystr- 7}

per stampare un messaggio di errore ed uscire dalla funzione se la variabile non è definita:

: ${mystr? not defined}

Fai attenzione qui che ho usato ':' per non avere il contenuto di $ mystr eseguito come comando nel caso in cui sia definito.

Un riepilogo dei test.

[ -n "$var" ] && echo "var is set and not empty"
[ -z "$var" ] && echo "var is unset or empty"
[ "${var+x}" = "x" ] && echo "var is set"  # may or may not be empty
[ -n "${var+x}" ] && echo "var is set"  # may or may not be empty
[ -z "${var+x}" ] && echo "var is unset"
[ -z "${var-x}" ] && echo "var is set and empty"

https://stackoverflow.com/a/9824943/14731 contiene una risposta migliore (una più leggibile e funziona con set -o nounset abilitato). Funziona più o meno in questo modo:

if [ -n "${VAR-}" ]; then
    echo "VAR is set and is not empty"
elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then
    echo "VAR is set, but empty"
else
    echo "VAR is not set"
fi

Il modo esplicito di verificare la presenza di una variabile definita sarebbe:

[ -v mystr ]

un'altra opzione: l'elenco " indici di array " espansione :

$ unset foo
$ foo=
$ echo ${!foo[*]}
0
$ foo=bar
$ echo ${!foo[*]}
0
$ foo=(bar baz)
$ echo ${!foo[*]}
0 1

l'unica volta che questo si espande nella stringa vuota è quando foo non è impostato, quindi puoi controllarlo con la stringa condizionale:

$ unset foo
$ [[ ${!foo[*]} ]]; echo $?
1
$ foo=
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=bar
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=(bar baz)
$ [[ ${!foo[*]} ]]; echo $?
0

dovrebbe essere disponibile in qualsiasi versione bash > = 3.0

non perdere ancora questa bici, ma volevo aggiungere

shopt -s -o nounset

è qualcosa che potresti aggiungere all'inizio di uno script, il che causerà un errore se le variabili non sono dichiarate in nessun punto dello script. Il messaggio che visualizzerai è unbound variable, ma come altri citano non catturerà una stringa vuota o un valore null. Per accertarci che ogni singolo valore non sia vuoto, possiamo testare una variabile poiché viene espansa con ${mystr:?}, nota anche come espansione del simbolo del dollaro, che verrebbe a mancare con parameter null or not set.

Il Bash Reference Manual è una fonte autorevole di informazioni su bash.

Ecco un esempio di test di una variabile per vedere se esiste:

if [ -z "$PS1" ]; then
        echo This shell is not interactive
else
        echo This shell is interactive
fi

(Da sezione 6.3.2 .)

Nota che lo spazio bianco dopo l'apertura [ e prima di ] è non opzionale .


Suggerimenti per gli utenti di Vim

Avevo uno script che aveva diverse dichiarazioni come segue:

export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"

Ma volevo che rimandassero a qualsiasi valore esistente. Quindi li ho riscritti per assomigliare a questo:

if [ -z "$VARIABLE_NAME" ]; then
        export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
fi

Sono stato in grado di automatizzare questo in vim usando una regex veloce:

s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r  export \1=\2\rfi\r/gc

Questo può essere applicato selezionando visivamente le righe pertinenti, quindi digitando :. La barra dei comandi precompila con :'<,'>. Incolla il comando sopra e premi invio.


Testato su questa versione di Vim:

VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58)
Compiled by root@apple.com

Gli utenti di Windows potrebbero desiderare terminazioni di linea diverse.

Ecco quello che penso sia un modo molto più chiaro per verificare se una variabile è definita:

var_defined() {
    local var_name=$1
    set | grep "^${var_name}=" 1>/dev/null
    return $?
}

Usalo come segue:

if var_defined foo; then
    echo "foo is defined"
else
    echo "foo is not defined"
fi

set di chiamate senza argomenti .. genera tutti i parametri definiti ..
gli ultimi nell'elenco sarebbero quelli definiti nel tuo script.
così puoi indirizzare il suo output a qualcosa che possa capire quali cose sono definite e cosa no

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top