Aufzucht und Hege von Shell-Scripts: Variablen
Gültigkeit von Variablen
Eine in der Shell mit VAR=wert definierte Variable ist in dieser Shell (und nur in dieser) bekannt. Wenn Ihr in eine Subshell abtaucht, dann kennt man sie dort nicht mehr. Um eine Variable in den Subshells bekannt zu machen, müsst Ihr sie exportieren:
jan@jack:~/tmp> VAR=1
jan@jack:~/tmp> sh -c "echo $VAR" # $VAR wird in der aktuellen Shell expandiert
1
jan@jack:~/tmp> sh -c 'echo $VAR' # $VAR wird in der Subshell expandiert
jan@jack:~/tmp> export VAR # Export
jan@jack:~/tmp> sh -c 'echo $VAR' # jetzt ist $VAR in der Subshell bekannt
1
jan@jack:~/tmp> VAR=2
jan@jack:~/tmp> sh -c 'echo $VAR' # eine Wertänderung erfordert keinen neuen export
2
Was nie funktioniert: Variablenänderungen in einer Subshell an die aufrufende Shell hochzureichen. Das wird besonders dann gern vergessen, wenn man z. B. eine while-Schleife über eine Pipe füttert - eine Pipe macht eine Subshell auf (siehe auch Sub-Shells):
jan@jack:~/tmp> sh -c 'VAR=3' jan@jack:~/tmp> echo $VAR 2 jan@jack:~/tmp> ls | while read x; do VAR=$x; done jan@jack:~/tmp> echo $VAR 2
Es gibt zwei Möglichkeiten, die ermittelten Werte nach oben durchzureichen: den Wert auf STDOUT auszugeben und in der aufrufenden Shell per Kommandosubstitution "einzufangen", oder auf Subshells zu verzichten (zu diesem Thema siehe die nächsten Abschnitte):
jan@jack:~/tmp> VAR=`sh -c 'VAR=$((VAR + 1)); echo $VAR'` jan@jack:~/tmp> echo $VAR 3
In der "globalen" Gültigkeit von Shell-Variablen liegt eine Falle, besonders für rekursiv arbeitende Funktionen. Dazu ein kleines, ziemlich sinnfreies Beispiel:
function rekursiv {
# ein Zaehler
zahl=0
# Rekursionstiefe, wird mir uebergeben, ich zaehle 1 hoch
tiefe=`expr $1 + 1`
# Schleife, solange $zahl kleiner 3 und Rekursionstiefe kleiner 3
while test $zahl -le 2 -a $tiefe -le 2
do
# ich gebe meine Werte aus
echo "zahl=$zahl tiefe=$tiefe"
# ich steige eine Rekursionsebene hinab
rekursiv $tiefe
# Falle! Hier ist $tiefe bereits 2, da sie global gueltig ist
# und in den Rekursionen hochgezaehlt wurde
zahl=`expr $zahl + 1`
# hier Schleifenausstig, weil Ende-Bedingung erreicht ist. Durchlauf mit $zahl = 1
# findet nie statt
done
}
Dem Problem kann man zumindest in der Bash begegnen, wenn man die Variablen lokal definiert:
function rekursiv {
# ein Zaehler
local zahl=0
# Rekursionstiefe, wird mir uebergeben, ich zaehle 1 hoch
local tiefe=`expr $1 + 1`
...
}

