Utilisation de «$ {a: -b}» pour l'affectation de variable dans les scripts


429

J'ai consulté quelques scripts écrits par d'autres personnes (en particulier Red Hat), et bon nombre de leurs variables sont affectées à l'aide de la notation suivante VARIABLE1="${VARIABLE1:-some_val}" ou 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 at-il des avantages à cette notation ou des erreurs possibles qui pourraient être évitées?

Le a-t- :-il une signification spécifique dans ce contexte?


Jetez un oeil à man bash; recherchez le bloc "Parameter Expansion" (environ 28%). Ces assignations sont par exemple des fonctions par défaut: "Utilisez la valeur par défaut uniquement si aucune n'a encore été définie."
Hauke ​​Laging

Réponses:


701

Cette technique permet d'attribuer une valeur à une variable si une autre variable est vide ou non définie. Remarque: cette "autre variable" peut être la même ou une autre variable.

extrait

${parameter:-word}
    If parameter is unset or null, the expansion of word is substituted. 
    Otherwise, the value of parameter is substituted.

REMARQUE: Ce formulaire fonctionne également ${parameter-word}. Si vous souhaitez voir une liste complète de toutes les formes d'expansion de paramètres disponibles dans Bash, je vous suggère vivement de jeter un coup d'œil à cette rubrique dans le wiki de Bash Hacker intitulé " Expansion des paramètres ".

Exemples

la variable n'existe pas
$ echo "$VAR1"

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
default value
la variable existe
$ VAR1="has value"
$ echo "$VAR1"
has value

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
has value

La même chose peut être faite en évaluant d'autres variables ou en exécutant des commandes dans la partie valeur par défaut de la notation.

$ VAR2="has another value"
$ echo "$VAR2"
has another value
$ echo "$VAR1"

$

$ VAR1="${VAR1:-$VAR2}"
$ echo "$VAR1"
has another value

Plus d'exemples

Vous pouvez également utiliser une notation légèrement différente là où c'est juste VARX=${VARX-<def. value>}.

$ echo "${VAR1-0}"
has another value
$ echo "${VAR2-0}"
has another value
$ echo "${VAR3-0}"
0

Dans ce qui précède $VAR1et $VAR2déjà défini par la chaîne « a une autre valeur » , mais $VAR3était définie, la valeur par défaut a été utilisé à la place, 0.

Un autre exemple

$ VARX="${VAR3-0}"
$ echo "$VARX"
0

Vérifier et assigner en utilisant la :=notation

Enfin , je mentionnerai l'opérateur à portée de main, :=. Cela fera une vérification et assignera une valeur si la variable à tester est vide ou non définie.

Exemple

Notez que $VAR1c'est maintenant réglé. L’opérateur a :=fait le test et l’affectation en une seule opération.

$ unset VAR1
$ echo "$VAR1"

$ echo "${VAR1:=default}"
default
$ echo "$VAR1"
default

Cependant, si la valeur est définie auparavant, elle est laissée seule.

$ VAR1="some value"
$ echo "${VAR1:=default}"
some value
$ echo "$VAR1"
some value

Table de référence Handy Dandy

    ss de table

Références


8
Notez que toutes ces extensions ne sont pas documentées dans bash. Celui ${var:-word}du Q est, mais pas celui ${var-word}ci - dessus. La documentation POSIX a un joli tableau, mais il vaut peut-être la peine de la copier dans cette réponse - pubs.opengroup.org/onlinepubs/9699919799/utilities/…
Graeme le

5
@Graeme, cela est documenté, il vous suffit de faire attention aux résultats suivants
Stéphane Chazelas

7
Utiliser echo "${FOO:=default}"est génial si vous voulez réellement le echo. Mais si vous ne le faites pas, essayez la fonction :intégrée ... : ${FOO:=default} Votre $FOOconfiguration est la suivante default(c’est-à-dire si elle n’a pas déjà été définie). Mais il n'y a pas d'écho $FOOdans le processus.
fbicknel

2
Ok, a trouvé une réponse: stackoverflow.com/q/24405606/1172302 . Utiliser le ${4:-$VAR}travail va.
Nikos Alexandris

1
Ici, un +1 pour vous amener à 500. Félicitations! :)
XtraSimplicity

17

@slm a déjà inclus les documents POSIX - qui sont très utiles - mais ils ne développent pas vraiment la manière dont ces paramètres peuvent être combinés pour s’affecter 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 d’ une autre de mes réponses , et je pense que cela 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 profite de toutes les 4 formes de substitution de paramètres et de leurs différents POSIX :colon nullou not nulltests. Il y a plus d'informations dans le lien ci-dessus, et le voici à nouveau .

Une autre chose à laquelle les gens ne pensent souvent pas, ${parameter:+expansion}c'est à quel point cela peut être utile dans un document ici. Voici un autre extrait d'une réponse différente :

HAUT

Ici, vous définissez des valeurs par défaut et vous préparez à les imprimer lorsque vous êtes 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

MILIEU

C'est ici que vous définissez d'autres fonctions pour appeler 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
    }

BAS

Vous avez tout configuré maintenant, alors voici où vous allez exécuter et extraire vos résultats.

    _less_important_function
    : "${PLACE:="the cemetery"}" 
    _more_important_function
    : "${RESULT:="regret it."}" 
    _less_important_function    

RÉSULTATS

J'expliquerai 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 votre mère et j'ai vu Disney sur glace.

Si vous faites la calligraphie, vous réussirez.

ensuite _more_important_function():

Je suis allé au cimetière et j'ai vu Disney sur glace.

Si vous faites des mathématiques correctives, vous réussirez.

_less_important_function() encore:

Je suis allé au cimetière et j'ai vu Disney sur glace.

Si vous faites des mathématiques correctives, vous le regretterez.

COMMENT ÇA FONCTIONNE:

La caractéristique clé ici est le concept de conditional ${parameter} expansion.Vous pouvez définir une variable sur une valeur uniquement si elle est non définie ou nulle en utilisant le formulaire:

${var_name: =desired_value}

Si, au lieu de cela, vous souhaitez définir uniquement une variable non définie, vous omettez les :colonvaleurs et null resteraient telles quelles.

SUR LA PORTÉE:

Vous remarquerez peut-être que, dans l'exemple ci-dessus $PLACE, les $RESULTmodifications sont apportées lorsqu'elles sont définies via parameter expansionmême si elles _top_of_script_pr()ont déjà été appelées, probablement en les configurant lors de leur exécution. La raison pour laquelle cela fonctionne est que _top_of_script_pr()c'est une ( subshelled )fonction - je l'ai incluse parensplutôt que celle { curly braces }utilisée pour les autres. Comme elle est appelée dans un sous-shell, toutes les variables qu'elle définit sont locally scopedet, à mesure qu'elles retournent dans leur shell parent, ces valeurs disparaissent.

Mais lorsqu’il est _more_important_function()défini, $ACTIONil en va de même globally scopedpour la _less_important_function()'sdeuxième évaluation $ACTIONcar _less_important_function(), $ACTIONuniquement via${parameter:=expansion}.


1
Il est bon de voir que la valeur par défaut abrégée fonctionne dans Bourne Shell
Sridhar Sarnobat

8

Expérience personnelle.

J'utilise parfois ce format dans mes scripts pour minimiser les valeurs ad-hoc, 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 à changer la valeur par défaut d'origine de SOMETHING.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.