Angenommen, ich habe den folgenden Code:
# Check if the color prompt is enabled and supported on this system
if [ -n "$force_color_prompt" ] && [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
GREEN="\033[1;32m"
DIM="\033[2m"
RESET="\033[00m"
fi
echo -e "Oh, ${GREEN}green${RESET} world, ${DIM}don't desert me now...${RESET}"
Wenn die Farbunterstützung aktiviert ist, wird eine schöne, farbige Linie ausgegeben. Wenn die Farbunterstützung nicht aktiviert ist, sind Werte wie ${GREEN}
nicht festgelegt und der Text wird im üblichen Weiß mit schwarzem Hintergrund ausgedruckt.
Der Code basiert auf der Tatsache, dass Variablen, die nicht gesetzt sind, einfach als leere Zeichenfolge ausgewertet werden (was bei meinen Tests der Fall ist). Wird dies auf einigen Systemen zu Fehlern oder Problemen führen, oder werden alle nicht vorhandenen Variablenstetsals leere Zeichenfolge auswerten? Gibt es einen Grund, warum ich mich nicht auf diese Mechanik verlassen sollte?
Antwort1
Nicht vorhandene Variablen werden bei einer Erweiterung als $FOO
oder (äquivalent) immer als leerer String ausgewertet ${FOO}
und es ist nicht schädlich, sich darauf zu verlassen, außer in einem besonderen Fall:
Wenn jemand set -u
die aktuelle Shell aufgerufen hat, bevor Sie versucht haben, diese Variable zu verwenden, hat er diese Einstellung aktiviert:
-u Nicht gesetzte Variablen bei der Ausführung von Parametern als Fehler behandeln. eter-Erweiterung. Wenn die Erweiterung auf einem nicht gesetzten Variable, gibt die Shell eine Fehlermeldung aus, und wenn nicht interaktiv, wird mit einem Status ungleich Null beendet.
Dies bedeutet, dass Sie beim Schreiben einer Funktion, die in ein Skript eingebunden werden soll, das von jemand anderem gesteuert wird, vorsichtig sein müssen, was die Verwendung nicht gesetzter Variablen angeht. Andernfalls set -u
würde das Skript beim ersten Versuch, eine nicht gesetzte Variable zu erweitern, mit einer Fehlermeldung beendet, wenn die betreffende Person diese vor dem Aufruf Ihrer Funktion verwendet hätte.
Wenn Sie Ihr eigenes Skript schreiben, kann es nicht schaden, darauf zu zählen, dass nicht gesetzte Variablen zu einer leeren Zeichenfolge erweitert werden.
BEARBEITEN- Außerdem nur so ein Gedanke: Da Sie das Ganze davon abhängig machen, ob die Farbfunktionen von Terminfo für Ihr Terminal verfügbar sind, warum verwenden Sie dann nicht tatsächlich Terminfo zum Generieren der Sequenzen, anstatt die vt100-Werte fest zu codieren? So etwas wie:
if [ -n "$force_color_prompt" ] && type tput &>/dev/null; then
GREEN="$(tput setaf 2)$(tput bold)"
DIM="$(tput dim)"
RESET="$(tput sgr0)"
fi
Dies kann Ihnen etwas Portabilität zwischen anderen Terminals verschaffen (obwohl zugegebenermaßen die Anzahl der Terminals, die die von Ihnen angezeigten Codes nicht verwenden, klein ist und abnimmt). Es kann auch etwas Portabilität verloren gehen, da einige Funktionen auf einigen Plattformen möglicherweise nicht vorhanden sind, je nachdem, wie korrekt die Terminfo-Definitionen sind. Ihre Abweichung ist nicht genau.
Antwort2
Eines der einzigartigsten Merkmale der POSIX-kompatiblen Shell-Skriptsprache istParametererweiterung. Es kann auf verschiedene Weise verwendet werden, um Aufgaben auszuführen, die normalerweise nicht mit variablen Werten in Verbindung gebracht werden. In der Shell kann eine Variable mehr als nur ein Wert sein – sie kann ein ausführbares Element sein. Sie kann sich selbst testen. Und das geschieht explizit – ohne dass Shell-Optionen festgelegt werden müssen.
Ihr Code könnte beispielsweise so aussehen:
N= ERR='error encountered - exiting'
: ${force_color_prompt?"$ERR"}
/usr/bin/tput setaf >/dev/null 2>&1 || ${N:?"$ERR"}
: "${GREEN:=\033[1;32m}" "${DIM:=\033[2m}" "${RESET:=\033[00m}"
printf %b\\n \
"Oh, ${GREEN}green${RESET} world, ${DIM}don't desert me now...${RESET}"
Die $N
Variable wird explizit auf die Nullzeichenfolge gesetzt. Wenn sie also mit der ${N:?}
Form einer Parametererweiterung ausgewertet wird, wird ihre übergeordnete Shell automatisch beendet und die folgende Anweisung ?
wird ebenfalls auf Erweiterung ausgewertet. Die Ergebnisse werden auf ausgegeben stderr
. Dasselbe gilt für $force_color_prompt
-. Wenn sie nicht gesetzt ist, wird das Skript mit einem Fehler beendet und gibt automatisch $ERR
auf - all aus.stderr
Die $GREEN
$RESET
und werden auf die von Ihnen definierten Werte gesetzt, wenn sie entweder aktuell nicht gesetzt sind oder auf die Nullzeichenfolge $DIM
gesetzt sind . Dadurch können Sie ihre Werte als Umgebungsvariablen an das Skript übergeben. Wenn sich beispielsweise der obige Ausschnitt in einem Skript mit dem Namen befände und ich es folgendermaßen aufgerufen hätte:''
greenworld.sh
GREEN="$(tput setaf 2)$(tput bold)" greenworld.sh
Dann $GREEN
würde der Inhalt des Skripts nicht zurückgesetzt, sondern würde stattdessen den expliziten Wert übernehmen, den ich dafür festgelegt habe. Dies macht Shell-Skripte flexibel.
Und tput
ich persönlich unterstütze die Empfehlung dieser Verwendung, die godlygeek empfohlen hat.
In der Shell kann eine nicht gesetzte Variable manchmal genauso nützlich sein wie eine gesetzte. Hier ist ein anderes Beispiel:
set -- *
while ${1+:} false ; do
#do stuff until all positionals are shifted away
shift ; done
In diesem Beispiel wird der erste Parameter, solange er definiert ist, auf das eingebaute :
Null der Shell erweitert, was den folgenden false
Aufruf folglich zu einem No-Op macht. Sobald jedoch alle Positionsparameter shift
entfernt wurden ${1}
, wird es nicht mehr auf diese Weise erweitert und false
aufgerufen, und die while
Schleife endet. Sie können unzählige Variationen davon machen.
Antwort3
Im normalen Gebrauch, d. h. wenn Sie nur Variablen erweitern, wird eine nicht gesetzte Variable in allen Shells im Bourne/POSIX-Stil als leer behandelt. Die Ausnahme ist, wenn set -o unset
aka set -u
aktiv ist. In diesem Fall wird die Shell einen Fehler ausgeben, wenn Sie versuchen, auf den Wert einer nicht gesetzten Variable zuzugreifen (siehegodlygeeks Antwort).
Es gibt Möglichkeiten zu testen, ob eine Variable nicht gesetzt oder leer ist. Beispielsweise wird die Konstruktion ${foo-bar}
auf den Wert von erweitert, foo
wenn sie gesetzt ist (selbst wenn sie leer ist), und auf, bar
wenn foo
sie nicht gesetzt ist;${foo:-bar}
(mit einem zusätzlichen Doppelpunkt) behandelt eine leere Variable, als wäre sie nicht gesetzt. Andere ähnliche Erweiterungskonstruktionen ${foo+bar}
, ${foo?bar}
, ${foo=bar}
verhalten sich ähnlich. Eine leere Variable erscheint neben anderen Unterschieden auch in der Ausgabe von set
und export
(falls exportiert). Sie werden nur auf diese Unterschiede stoßen, wenn Sie möchten.
Es gibt jedoch einen anderen Grund,Variablen immer initialisieren: Woher wissen Sie, dass die Variable wirklich nicht gesetzt ist? Der Anrufer hat möglicherweise eine ähnliche Variable für seine eigenen Zwecke definiert. Wenn der Anrufer ein anderer Teil desselben Skripts ist, überschreibt Ihre Verwendung in einer Funktion die des Anrufers, es sei denn, Sie deklarieren die Variable als lokal (was nur in ksh/bash/zsh möglich ist), sodass Variablennamenkonflikte ohnehin ein Problem darstellen. Es kann aber auch vorkommen, dass die Variable in der Umgebung vorhanden ist, weil jemand anderes denselben Variablennamen wie Sie gewählt hat. Es gibt eine Art Konvention, Kleinbuchstaben für Shellvariablen und Großbuchstaben für Umgebungsvariablen zu verwenden, aber das löst nicht alle Konflikte und wird nicht allgemein befolgt.
$ export DIM=1 SUM=42 $ bash Oh, grüne Welt, ich lass mich jetzt nicht im Stich ...