Ho esaminato alcuni script scritti da altre persone (in particolare Red Hat) e molte delle loro variabili sono assegnate utilizzando la seguente notazione VARIABLE1="${VARIABLE1:-some_val}"
o altre espansioni variabili VARIABLE2="${VARIABLE2:-`echo $VARIABLE1`}"
Qual è il punto di utilizzare questa notazione invece di dichiarare direttamente i valori (ad esempio, VARIABLE1=some_val
)?
Ci sono vantaggi in questa notazione o possibili errori che potrebbero essere evitati?
:-
ha un significato specifico in questo contesto ?
Commenti
Risposta
Questa tecnica consente di assegnare un valore a una variabile se unaltra variabile è vuota o non è definita. NOTA: questa “altra variabile” può essere la stessa o unaltra variabile.
estratto
${parameter:-word} If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.
NOTA: funziona anche il modulo, ${parameter-word}
. Se “desideri vedere un elenco completo di tutte le forme di espansione dei parametri disponibili in Bash, ti consiglio caldamente di dare unocchiata a questo argomento nel wiki di Bash Hacker” dal titolo: “ Espansione parametro “.
Esempi
la variabile non” esiste
$ echo "$VAR1" $ VAR1="${VAR1:-default value}" $ echo "$VAR1" default value
variabile esiste
$ VAR1="has value" $ echo "$VAR1" has value $ VAR1="${VAR1:-default value}" $ echo "$VAR1" has value
La stessa cosa può essere eseguita valutando altre variabili o eseguendo comandi allinterno della parte del valore predefinito della notazione.
$ VAR2="has another value" $ echo "$VAR2" has another value $ echo "$VAR1" $ $ VAR1="${VAR1:-$VAR2}" $ echo "$VAR1" has another value
Altri esempi
Puoi anche utilizzare una notazione leggermente diversa in cui “è solo VARX=${VARX-<def. value>}
.
$ echo "${VAR1-0}" has another value $ echo "${VAR2-0}" has another value $ echo "${VAR3-0}" 0
In $VAR1
& $VAR2
erano già definiti con la stringa “has another value” ma $VAR3
non era definito, quindi è stato utilizzato il valore predefinito 0
.
Un altro esempio
$ VARX="${VAR3-0}" $ echo "$VARX" 0
Controllo e assegnazione utilizzando la notazione :=
Infine menzionerò loperatore pratico, :=
. Questo eseguirà un controllo e assegnerà un valore se la variabile sottoposta a test è vuota o non definita.
Esempio
Nota che $VAR1
è ora impostato. Loperatore :=
ha eseguito il test e lassegnazione in ununica operazione.
$ unset VAR1 $ echo "$VAR1" $ echo "${VAR1:=default}" default $ echo "$VAR1" default
Tuttavia, se il valore è impostato prima, poi è lasciato solo.
$ VAR1="some value" $ echo "${VAR1:=default}" some value $ echo "$VAR1" some value
Tabella di riferimento Handy Dandy
Riferimenti
- Espansioni dei parametri – Bash Hackers Wiki
- 10.2. Sostituzione dei parametri
- Bash Parameter Expansions
Commenti
- Nota che non tutte queste sono espansioni sono documentate in
bash
. Quello${var:-word}
nella Q è, ma non il${var-word}
sopra. Il POSIX la documentazione ha una bella tabella, potrebbe valere la pena copiarla in th è answer – pubs.opengroup.org/onlinepubs/9699919799/utilities/… - @Graeme, è documentato, devi solo prestare attenzione al Omettendo i due punti risulta in un test solo per un parametro non impostato.
- Utilizzando
echo "${FOO:=default}"
è ottimo se vuoi effettivamenteecho
. Ma se non ‘ t, prova il:
integrato …: ${FOO:=default}
Il tuo$FOO
è impostato sudefault
come sopra (cioè, se non è già impostato). Ma ‘ non cè eco di$FOO
nel processo. - Ok, ho trovato una risposta: stackoverflow.com / q / 24405606/1172302 . Lutilizzo del
${4:-$VAR}
funzionerà. - +1 solo per la risposta dettagliata. Ma anche per il fatto che fai riferimento alleccellente wiki di bash. E anche per il fatto che fornisci esempi e una tabella. Diamine, solo +1 fino in fondo 🙂 Per quanto mi riguarda avevo quasi la sintassi giusta ma non del tutto – semplicemente ‘ non mi interessava abbastanza da cercare nella pagina man (non difficile ma non riuscivo ‘ a ricordare sotto quale intestazione si trovava e ‘ sono sveglio dalle 4 di questa mattina :() ..
Risposta
@slm ha già incluso i documenti POSIX – che sono molto utili – ma in realtà non spiegano come questi parametri possono essere combinati per influenzarsi a vicenda. Non cè ancora alcuna menzione qui di questa forma:
${var?if unset parent shell dies and this message is output to stderr}
Questo è un estratto da unaltra mia risposta , e penso che dimostri molto bene come funzionano:
sh <<-\CMD _input_fn() { set -- "$@" #redundant echo ${*?WHERES MY DATA?} #echo is not necessary though shift #sure hope we have more than $1 parameter : ${*?WHERES MY DATA?} #: do nothing, gracefully } _input_fn heres some stuff _input_fn one #here # shell dies - third try doesnt run _input_fn you there? # END CMD heres some stuff one sh: line :5 *: WHERES MY DATA?
Un altro esempio da stesso :
sh <<-\CMD N= #N is NULL _test=$N #_test is also NULL and v="something you would rather do without" ( #this subshell dies echo "v is ${v+set}: and its value is ${v:+not NULL}" echo "So this ${_test:-"\$_test:="} will equal ${_test:="$v"}" ${_test:+${N:?so you test for it with a little nesting}} echo "sure wish we could do some other things" ) ( #this subshell does some other things unset v #to ensure it is definitely unset echo "But here v is ${v-unset}: ${v:+you certainly wont see this}" echo "So this ${_test:-"\$_test:="} will equal NULL ${_test:="$v"}" ${_test:+${N:?is never substituted}} echo "so now we can do some other things" ) #and even though we set _test and unset v in the subshell echo "_test is still ${_test:-"NULL"} and ${v:+"v is still $v"}" # END CMD v is set: and its value is not NULL So this $_test:= will equal something you would rather do without sh: line 7: N: so you test for it with a little nesting But here v is unset: So this $_test:= will equal NULL so now we can do some other things _test is still NULL and v is still something you would rather do without
Lesempio precedente sfrutta tutte e 4 le forme di sostituzione dei parametri POSIX e i loro vari test :colon null
o not null
. Sono disponibili ulteriori informazioni nel link sopra e eccole di nuovo .
Unaltra cosa che le persone spesso non considerano di ${parameter:+expansion}
è quanto possa essere molto utile in un here-document. Ecco un altro estratto da un risposta diversa :
TOP
Qui imposterai alcune impostazioni predefinite e ti preparerai a stamparle quando chiamate …
#!/bin/sh _top_of_script_pr() ( IFS="$nl" ; set -f #only split at newlines and don"t expand paths printf %s\\n ${strings} ) 3<<-TEMPLATES ${nl= } ${PLACE:="your mother"s house"} ${EVENT:="the unspeakable."} ${ACTION:="heroin"} ${RESULT:="succeed."} ${strings:=" I went to ${PLACE} and saw ${EVENT} If you do ${ACTION} you will ${RESULT} "} #END TEMPLATES
MIDDLE
Qui è dove definisci altre funzioni da chiamare sulla tua funzione di stampa in base ai loro risultati …
EVENT="Disney on Ice." _more_important_function() { #...some logic... [ $((1+one)) -ne 2 ] && ACTION="remedial mathematics" _top_of_script_pr } _less_important_function() { #...more logic... one=2 : "${ACTION:="calligraphy"}" _top_of_script_pr }
BOTTOM
Ora hai tutto configurato, quindi ecco dove eseguirai e recupererai i risultati.
_less_important_function : "${PLACE:="the cemetery"}" _more_important_function : "${RESULT:="regret it."}" _less_important_function
RISULTATI
Spiegherò il motivo tra un momento, ma lesecuzione di quanto sopra produce i seguenti risultati:
_less_important_function()"s
prima esecuzione:Sono andato a casa di tua madre e ho visto Disney on Ice.
Se fai calligrafia avrai successo.
th it
_more_important_function():
Sono andato al cimitero e ho visto Disney on Ice.
Se fai matematica correttiva avrai successo.
_less_important_function()
di nuovo:Sono andato al cimitero e ho visto Disney on Ice.
Se ti occupi di matematica correttiva, te ne pentirai.
COME FUNZIONA:
La caratteristica chiave qui è il concetto di conditional ${parameter} expansion.
Puoi impostare una variabile su un valore solo se non è impostato o è nullo utilizzando il formato:
${var_name
: =desired_value}
Se invece desideri impostare solo una variabile non impostata, ometti il e i valori null rimarrebbero come sono.
IN AMBITO:
Potresti notare che nellesempio precedente $PLACE
e $RESULT
vengono modificati se impostati tramite parameter expansion
anche se _top_of_script_pr()
è già stato chiamato, presumibilmente impostandoli quando viene eseguito. Il motivo per cui funziona è che _top_of_script_pr()
è una funzione ( subshelled )
– ho incluso in parens
anziché in { curly braces }
utilizzato per gli altri. Poiché è chiamata in una subshell, ogni variabile che imposta è locally scoped
e quando ritorna alla sua shell genitrice quei valori scompaiono.
Ma quando _more_important_function()
imposta $ACTION
è globally scoped
quindi influisce sulla _less_important_function()"s
seconda valutazione di $ACTION
perché _less_important_function()
imposta $ACTION
solo tramite ${parameter:=expansion}.
Commenti
- È bello vedere che il valore predefinito della scorciatoia funziona in Bourne Shell
Risposta
Esperienza personale.
A volte utilizzo questo formato nei miei script per sovrascrivere i valori ad hoc, ad es.se ho:
$ cat script.sh SOMETHING="${SOMETHING:-something}"; echo "$SOMETHING";
posso eseguire:
$ env SOMETHING="something other than the default value" ./script.sh`
senza dover modificare il valore predefinito originale di SOMETHING
.
man bash
; cerca il blocco ” Parameter Expansion ” (al 28% circa). Questi incarichi sono ad es. funzioni predefinite: ” Utilizza il valore predefinito solo se non ne è stato ancora impostato nessuno. ”:-
imposta il valore predefinito,:+
viene utilizzato per alterare il valore se la variabile è non nullo. Per esempio.v=option; cmd ${v:+ with $v}
Verrà eseguito ” cmd con lopzione “. Ma se $ v è nullo, verrà eseguito solo ” cmd “.