J'ai regardé quelques scripts écrits par d'autres personnes (en particulier Red Hat), et beaucoup de leurs variables sont affectées en utilisant la notation suivante VARIABLE1="${VARIABLE1:-some_val}"
ou certains développent d'autres variables VARIABLE2="${VARIABLE2:-`echo $VARIABLE1`}"
Quel est l'intérêt d'utiliser cette notation au lieu de simplement déclarer les valeurs directement (par exemple, VARIABLE1=some_val
)?
Y a-t-il des avantages à cette notation ou des erreurs possibles qui pourraient être évitées?
Est-ce que le :-
ont une signification particulière dans ce contexte?
@slm a déjà inclus les documents POSIX - qui sont très utiles - mais ils ne développent pas vraiment la façon dont ces paramètres peuvent être combinés pour s'influencer mutuellement. Il n'y a pas encore de mention ici de ce formulaire:
${var?if unset parent Shell dies and this message is output to stderr}
Ceci est un extrait de ne autre réponse à moi, et je pense qu'il montre très bien comment cela fonctionne:
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 autre exemple de même :
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
L'exemple ci-dessus tire parti des 4 formes de substitution de paramètres POSIX et de leurs différents tests :colon null
ou not null
. Il y a plus d'informations dans le lien ci-dessus, et le voici à nouvea .
Une autre chose que les gens ne considèrent souvent pas à propos de ${parameter:+expansion}
Est de savoir à quel point cela peut être utile dans un document ici. Voici un autre extrait d'un réponse différente :
Ici, vous allez définir des valeurs par défaut et vous préparer à les imprimer lors de l'appel ...
#!/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
C'est ici que vous définissez d'autres fonctions pour faire appel à votre fonction d'impression en fonction de leurs résultats ...
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
}
Vous avez tout configuré maintenant, alors voici où vous exécuterez et tirerez vos résultats.
_less_important_function
: "${PLACE:="the cemetery"}"
_more_important_function
: "${RESULT:="regret it."}"
_less_important_function
Je vais expliquer pourquoi dans un instant, mais l'exécution de ce qui précède produit les résultats suivants:
_less_important_function()'s
première exécution:Je suis allé chez ta mère et j'ai vu Disney on Ice.
Si vous faites calligraphie vous réussirez.
alors
_more_important_function():
Je suis allé au cimetière et j'ai vu Disney sur glace.
Si vous faites mathématiques de rattrapage vous réussirez.
_less_important_function()
à nouveau:Je suis allé au cimetière et j'ai vu Disney sur glace.
Si vous faites des mathématiques de rattrapage, vous allez le regretter.
La caractéristique clé ici est le concept de conditional ${parameter} expansion.
Vous ne pouvez définir une variable sur une valeur que si elle est non définie ou nulle en utilisant le formulaire:
${var_name
: =desired_value}
Si, à la place, vous souhaitez définir uniquement une variable non définie, vous omettez le :colon
et les valeurs nulles restent inchangées.
Vous remarquerez peut-être que dans l'exemple ci-dessus $PLACE
et $RESULT
sont modifiés lorsqu'ils sont définis via parameter expansion
même si _top_of_script_pr()
a déjà été appelé, les définissant probablement lors de son exécution. La raison pour laquelle cela fonctionne est que _top_of_script_pr()
est une fonction ( subshelled )
- Je l'ai incluse dans parens
plutôt que le { curly braces }
utilisé pour les autres. Parce qu'elle est appelée dans un sous-shell, chaque variable qu'elle définit est locally scoped
et lorsqu'elle revient à son shell parent, ces valeurs disparaissent.
Mais quand _more_important_function()
définit $ACTION
c'est globally scoped
= donc cela affecte _less_important_function()'s
seconde évaluation de $ACTION
car _less_important_function()
définit $ACTION
uniquement via ${parameter:=expansion}.
Expérience personnelle.
J'utilise parfois ce format dans mes scripts pour effectuer un remplacement ad hoc des valeurs, par exemple si j'ai:
$ cat script.sh
SOMETHING="${SOMETHING:-something}"; echo "$SOMETHING";
Je peux courir:
$ env SOMETHING="something other than the default value" ./script.sh`
sans avoir à modifier la valeur par défaut d'origine de SOMETHING
.