Verwenden von "$ {a: -b}" für die Variablenzuweisung in Skripten

426

Ich habe mir ein paar Skripte angesehen, die andere geschrieben haben (insbesondere Red Hat), und viele ihrer Variablen wurden mit der folgenden Notation zugewiesen VARIABLE1="${VARIABLE1:-some_val}" oder einige erweitern andere Variablen VARIABLE2="${VARIABLE2:-`echo $VARIABLE1`}"

Was bringt es, diese Notation zu verwenden, anstatt nur die Werte direkt zu deklarieren (z. B. VARIABLE1=some_val)?

Gibt es Vorteile für diese Notation oder mögliche Fehler, die verhindert würden?

Hat das :-in diesem Zusammenhang eine bestimmte Bedeutung?

Rothgar
quelle
Schauen Sie sich an man bash; Suchen Sie nach dem Block "Parametererweiterung" (bei ca. 28%). Diese Zuweisungen sind z. B. Standardfunktionen: "Verwenden Sie den Standardwert nur, wenn noch keine festgelegt wurden."
Hauke ​​Laging

Antworten:

696

Mit dieser Technik kann einer Variablen ein Wert zugewiesen werden, wenn eine andere Variable leer oder undefiniert ist. HINWEIS: Diese "andere Variable" kann dieselbe oder eine andere Variable sein.

Auszug

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

HINWEIS: Dieses Formular funktioniert auch ${parameter-word}. Wenn Sie eine vollständige Liste aller in Bash verfügbaren Formen der Parametererweiterung sehen möchten, empfehle ich Ihnen dringend, sich dieses Thema im Wiki von Bash Hacker mit dem Titel " Parametererweiterung " anzuschauen .

Beispiele

Variable existiert nicht
$ echo "$VAR1"

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

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

Das Gleiche kann durch Auswerten anderer Variablen oder durch Ausführen von Befehlen im Standardwertteil der Notation erreicht werden.

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

$

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

Mehr Beispiele

Sie können auch eine etwas andere Notation verwenden, wenn es nur so ist VARX=${VARX-<def. value>}.

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

Oben wurde $VAR1& $VAR2bereits mit der Zeichenfolge "hat einen anderen Wert" $VAR3definiert, war jedoch undefiniert, sodass stattdessen der Standardwert verwendet wurde 0.

Ein anderes Beispiel

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

Prüfen und Zuweisen mit :=Notation

Zuletzt erwähne ich den praktischen Operator :=. Dies führt eine Überprüfung durch und weist einen Wert zu, wenn die zu testende Variable leer oder undefiniert ist.

Beispiel

Beachten Sie, dass $VAR1jetzt eingestellt ist. Der Bediener :=erledigte den Test und die Aufgabe in einem Arbeitsgang.

$ unset VAR1
$ echo "$VAR1"

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

Wenn der Wert jedoch zuvor festgelegt wurde, bleibt er in Ruhe.

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

Handy Dandy Referenztabelle

    ss der Tabelle

Verweise

slm
quelle
8
Beachten Sie, dass nicht alle dieser Erweiterungen in dokumentiert sind bash. Die ${var:-word}im Q ist, aber nicht die ${var-word}oben. Die POSIX-Dokumentation hat jedoch eine schöne Tabelle, die es möglicherweise wert ist, in diese Antwort kopiert zu werden - pubs.opengroup.org/onlinepubs/9699919799/utilities/…
Graeme
5
@Graeme, es ist dokumentiert, Sie müssen nur darauf achten, dass das Auslassen des Doppelpunkts nur einen Test für einen Parameter ergibt, der nicht gesetzt ist.
Stéphane Chazelas
7
Verwenden echo "${FOO:=default}"ist toll, wenn Sie tatsächlich die wollen echo. Aber wenn Sie dies nicht tun, versuchen Sie es mit dem :eingebauten ... : ${FOO:=default} Ihr $FOOist defaultwie oben eingestellt (dh wenn nicht bereits eingestellt). Aber es gibt kein Echo $FOOin dem Prozess.
fbicknel
2
Ok, fand eine Antwort: stackoverflow.com/q/24405606/1172302 . Die Verwendung des ${4:-$VAR}wird funktionieren.
Nikos Alexandris
1
Hier haben Sie eine +1, um Sie auf 500 zu bringen. Herzlichen Glückwunsch! :)
XtraSimplicity
17

@slm hat bereits die POSIX-Dokumente enthalten, die sehr hilfreich sind, aber nicht wirklich erläutern , wie diese Parameter kombiniert werden können, um sich gegenseitig zu beeinflussen. Dieses Formular ist hier noch nicht erwähnt:

${var?if unset parent shell dies and this message is output to stderr}

Dies ist ein Auszug aus einer anderen meiner Antworten , und ich denke, er zeigt sehr gut, wie diese funktionieren:

    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?

Ein weiteres Beispiel aus demselben :

    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

Das obige Beispiel nutzt alle 4 Formen der POSIX-Parametersubstitution und ihre verschiedenen :colon nulloder not nullTests. Es gibt mehr Informationen im obigen Link und hier ist es wieder .

Eine andere Sache, über die die Leute oft nicht nachdenken, ${parameter:+expansion}ist, wie nützlich sie in einem Here-Dokument sein kann. Hier ist ein weiterer Auszug aus einer anderen Antwort :

OBEN

Hier legen Sie einige Standardeinstellungen fest und bereiten das Drucken vor, wenn Sie dazu aufgefordert werden ...

#!/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

MITTE

Hier definieren Sie andere Funktionen, um Ihre Druckfunktion basierend auf deren Ergebnissen aufzurufen ...

    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
    }

UNTERSEITE

Sie haben jetzt alles eingerichtet. Hier können Sie Ihre Ergebnisse ausführen und abrufen.

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

ERGEBNISSE

Ich werde gleich auf das Warum eingehen, aber das Ausführen des obigen Befehls führt zu den folgenden Ergebnissen:

_less_important_function()'s erster Lauf:

Ich bin zum Haus deiner Mutter gegangen und habe Disney on Ice gesehen.

Wenn Sie Kalligraphie machen, werden Sie Erfolg haben.

dann _more_important_function():

Ich ging zum Friedhof und sah Disney on Ice.

Wenn Sie Heilmathematik machen, werden Sie Erfolg haben.

_less_important_function() nochmal:

Ich ging zum Friedhof und sah Disney on Ice.

Wenn Sie Heilmathematik machen, werden Sie es bereuen.

WIE ES FUNKTIONIERT:

Das Hauptmerkmal hierbei ist das Konzept von. conditional ${parameter} expansion.Sie können eine Variable nur dann auf einen Wert setzen, wenn sie in der folgenden Form nicht gesetzt oder null ist:

${var_name: =desired_value}

Wenn Sie stattdessen nur eine nicht festgelegte Variable :colonfestlegen möchten , lassen Sie die Werte weg, und Nullwerte bleiben unverändert .

ON SCOPE:

Möglicherweise bemerken Sie dies im obigen Beispiel $PLACEund $RESULTwerden geändert, wenn die Einstellung über ausgeführt wird parameter expansion, obwohl _top_of_script_pr()sie bereits aufgerufen wurde. Möglicherweise werden sie beim Ausführen festgelegt. Der Grund, warum dies funktioniert, ist, dass _top_of_script_pr()es sich um eine ( subshelled )Funktion handelt - ich habe sie eingeschlossen, parensanstatt { curly braces }sie für die anderen zu verwenden. Da es in einer Subshell aufgerufen wird, ist jede Variable, die es setzt, locally scopedund wenn es zu seiner übergeordneten Shell zurückkehrt, verschwinden diese Werte.

Aber wenn _more_important_function()legt $ACTIONes globally scopedso wirkt es _less_important_function()'szweite Auswertung von $ACTIONda _less_important_function()Sätze $ACTIONnur über${parameter:=expansion}.

mikeserv
quelle
1
Gut zu sehen, dass der Standardwert für die Kurzschrift in Bourne Shell
Sridhar Sarnobat am
8

Persönliche Erfahrung.

Ich verwende dieses Format manchmal in meinen Skripten, um Werte ad-hoc zu überschreiben, zB wenn ich Folgendes habe:

$ cat script.sh
SOMETHING="${SOMETHING:-something}"; echo "$SOMETHING"; 

Ich kann rennen:

$ env SOMETHING="something other than the default value" ./script.sh` 

ohne den ursprünglichen Standardwert von ändern zu müssen SOMETHING.

hjk
quelle