web-dev-qa-db-fra.com

Utilisation de "$ {a: -b}" pour l'affectation des variables dans les scripts

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?

499
Rothgar

@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 :

HAUT

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

MILIEU

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
    }

BAS

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    

RÉSULTATS

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.

COMMENT ÇA FONCTIONNE:

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.

SUR LA PORTÉE:

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}.

17
mikeserv

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.

10
h.j.k.