Variablen E-Mail
Geschrieben von: tpm   

Um unbekannte Werte (numerisch, alphabetisch oder gemischt) erfassen zu können, müssen der Shell feste Größen bekannt gemacht werden, die diese Werte als eine Art Container aufnehmen und ebenso wieder ausgeben können. Diese Container nennt man Variablen.

 

Variablen stehen für Zeichen oder Zeichenketten die unterschiedlichste Inhalte repräsentieren. Eine Variable unter Linux beginnt ein Variablebezeichner immer mit einem Buchstaben oder Unterstrich. Das ist das Mindestkriterium. Zur besseren Lesbarkeit folgen daraufhin in der Regel weitere Zeichen, die für den Programmierer in der Summe einen verständlichen Sinn ergeben sollten, so dass ihre Aufgabe auch im weiteren Arbeitsverlauf schnell zuzuordnen ist.

Die Variable wird initialisiert (dem System bekannt gemacht), in dem man ihr unmittelbar (ohne Leerzeichen) ein Gleichheitszeichen ( = ) anstellt. Dieser kann sowohl numerisch, alphabetisch oder gemischt sein.

Somit wäre die einfachste Form einer Variableninitialisierung:

 

example
variablenname=

 

In diesem Fall wird die Variable variablenname mit NULL initialisiert. NULL hat in der Shell die Bedeutung eines leeren Strings. Also weder die Zahl 0 noch nichts. Da diese Form beim Einsatz in der Kommandozeile wenig Sinn ergibt (in Scripten schon eher), folgt direkt ein praktisches Beispiel:

 

input
my_text='Hallo Welt!'

 

Wird die Initialisierung in dieser Form in der Shell durchgeführt, dann ist sie nur für den Dauer der Shell-Sitzung und nur für den jeweilgen Benutzer existent. Die beiden Hochkommas sind immer dann erforderlich, wenn eine Zeichenkette Leerzeichen beinhaltet. Damit wird die Zusammengehörigkeit gekennzeichnet.

Anmerkung: Hochkommas kommen noch eine besondere Bedeutung zu, die im weiteren Verlauf des Beitrags separat behandelt wird.

Soll die Variable nun angesprochen werden, ist ihr das Dollar-Zeichen ( $ ) voranzustellen:

 

input
echo $my_text

 

output
Hallo Welt!

 

Ebenso lassen sich Inhalte von Variablen auch wieder anderen Variablen zuordnen. An die erste Stelle kommt die Variable der etwas zugewiesen werden soll, nach dem Gleichheitszeichen die Variable von der zugewiesen wird.

 

input
my_new_text=$my_text

 

input
echo $my_new_text

 

output
Hallo Welt!

 

Nun besitzen beide Variablen (my_text und my_new_text) den selben Inhalt, repräsentieren dennoch zwei eigenständige Variablen. Das bedeutet, würde man den Inhalt einer Variablen ändern, wirkt sich diese Änderung nicht auf die andere Variable aus!

 

Wie bereits erwähnt, kommt einfachen und doppelten Hochkommas eine besondere Bedeutung zu. Allgemein werden beide Varianten verwendet, um die Zusammengehörigkeit von Zeichenketten zu markieren, die Leerstellen enthalten:

 

input
my_text="Das Ergebnis lautet:"

 

input
my_ergebnis='4578,34 Euro'

 

Diese Variablen wurden einmal mit einfachen und einmal mit doppelten Hochkommas initialisiert. Dies hätte auch genau so gut umgekehrt geschehen können. Dass ist an dieser Stelle erstmal ohne Bedeutung. Interessant wird es erst, wenn man diese Variablen weiterverarbeiten, beispielsweise zusammenhängend am Bildschirm ausgeben möchte:

 

input
echo '$my_text $my_ergebnis'

 

output
$my_text $my_ergebnis

 

...und nun mit doppelten Hochkommas...

 

input
echo "$my_text $my_ergebnis"

 

output
Das Ergebnis lautet: 4578,34 Euro

 

Was ist passiert? Die einfachen Hochkommas bewirken nicht etwa, dass die Variablennamen anstatt deren Inhalt ausgegeben werden. Sie werten Variablen (und Sonderzeichen) schlichtweg nicht aus, so dass die Ausgabe einfach eine Zeichenkette der Form $my_text $my_ergebnis darstellt. Nichts weiter. Die doppelten Hochkommas hingegen werten Variablen (und Sonderzeichen) aus.

 

Nun kann man in die Situation kommen, wo man auf die Verwendung der doppelten Hochkommas ( " ) angewiesen ist, aber ebenso auf die Verwendung von speziellen Zeichen, denen systemintern eine besondere Bedeutung zukommt. Dazu zählen das doppelte Hochkomma ( " ) selbst, das Dollar-zeichen ( $ ), das Backquote ( ` ) und der Backslash ( \ ). Da diese Sonderzeichen zu unerwünschten Ergebnissen führen würden, setzt man dem jeweiligen Sonderzeichen einfach ein Backslash ( \ ) vor.

Dies ist beispielsweise nützlich, wenn eine echo-Ausgabe Sonderzeichen enthält, aber gleichzeitig eine oder mehrere Variablen auswerten soll, was mit einfachen Hochkommas nicht ohne weiteres zu realisieren ist:

 

input
myVar='9876,50'
echo 'Die "rasch zu zahlende" Summe beträgt $myVar$'

 

output
Die "rasch zu zahlende" Summe beträgt $myVar$

 

Wie zu erwarten wurde alle systeminternen Sonderzeichen nicht ausgewertet. Allerdings führt dies gerade bei der Variablen nicht zu dem gewünschten Effekt. Dies lässt sich beheben, in dem man die doppelten Hochkommas verwendet und die Bedeutung der Sonderzeichen durch das Backslash aufhebt:

 

input
myVar='9876,50'
echo "Die \"rasch zu zahlende\" Summe beträgt $myVar\$"

 

output
Die "rasch zu zahlende" Summe beträgt 9876,50$

 

Anmerkung: Manche mögen sich mittlerweile Fragen, ob es keine generelle Regel dafür gibt, wann einfache und wann doppelte Hochkommas verwendet werden sollten. Leider gibt es dafür kein Pauschalrezept. Ich persönlich verwende wann immer möglich einfache Hochkommas. Nur wenn eine Auswertung durchgeführt werden soll, greife ich zu den doppelten Hochkommas. Letztendlich ist es aber eine reine Geschmackssache, so lange eben nicht eine bestimmte Variante zwingend erforderlich ist.

 

Im Bezug auf Variablen ist ihr Wirkungsbereich noch ein wichtiger Punkt der behandelt werden muss. Variablen können einen globalen oder einen lokalen Wirkungsbereich haben. Dazu gelten folgende Regeln:

  • Globale Variablen gelten nur für die Shell in der sie initialisiert wurden und für deren Kindprozesse.
  • Jeder Kindprozess einer Shell hat Zugriff auf eine Kopie einer globalen Variable.
  • Lokale Variablen gelten nur für die Shell, in der sie als initialisiert wurden und nicht für Kindprozesse.

 

Soll eine Variable als globale Variable definiert werden, wird dies mit dem export-Befehl realisiert:

 

example
export variablenname

 

...und wenn die Variable erst noch initialisiert werden muss, geht dies auch in einem Durchgang...

 

example
export variablenname=wert

 

 

Eine kleine Testreihe soll nun die Regeln für den Wirkungsbereich von Variablen untermauern. Dazu muss der Zugriff auf zwei Shell's gewährleistet sein, Auf einem lokalen System erreicht man dies durch die Tastenkombination Strg+F1, bzw. Strg+F2 und bei einem entfernten System öffnet man einfach zwei Shell-Sitzungen via SSH.

Zu Beginn werden zur besseren Differenzierung die Prozess-ID's der beiden Shell's ermittelt:

 

input
echo $$

 

output
9458

 

...ist in diesem Fall die Prozess-ID der ersten Shell.

 

output
9478

 

...ist in diesem Fall die Prozess-ID der zweiten Shell.

 

Nun werden in beiden Shell's jeweils die lokale Variable a und die globale Variable B mit unterschiedlichen Werten initialisiert:

 

input
a=11 ; export B=22

 

...in der ersten Shell (PID 9458).

 

input
a=33 ; export B=44

 

...in der zweiten Shell (PID 9478).

 

Anschließend wird von der ersten Shell (PID 9458) aus eine Subshell initialisiert und dann ihre aktuelle Prozess-ID erfragt, sowie die Prozess-ID des Mutterprozesses:

 

input
bash

 

input
echo $$ ; echo $PPID

 

output
9497
9458

 

 

Die Subshell hat hier die PID 9497 erhalten und mit dem Ergebnis 9458 ist verifiziert, dass die Subshell ein Kindprozess der ersten Shell (PID 9458) ist. In einem Diagramm sieht das Ganze dann so aus:

 

Wirkungsbereich von Variablen

 

Nun werden die Variablen abgefragt und manipuliert, um diese Änderungen in den jeweiligen Shell's zu überprüfen. Als erstes wird in der Subshell (PID 9497) versucht die lokale Variable a abzufragen:

 

input
echo $a

 

Als Ergebnis erhält man lediglich eine Leerzeile, da der Subshell diese Variable nicht bekannt ist. Dies belegt die Regel, dass lokale Variablen nur in der Shell bekannt sind, in der sie initialisiert wurden.

Anschließend wird die globale Variable B manipuliert, in dem ihr ein neuer Wert zugewiesen wird. Anschließend wird die Subshell (PID 9497) beendet, so dass man wieder an der Eingabeaufforderung der ersten Shell (PID 9458) steht:

 

input
B=100 ; exit

 

Nun wird die globale Variable B in der ersten Shell (PID 9458) abgefragt:

 

input
echo $B

 

output
22

 

Der Wert hat sich offensichtlich nicht geändert. Dies belegt die Regel, dass Subshell's lediglich eine Kopie einer globalen Variablen erhalten. Diese Kopie hat keinen Einfluss auf das Original und ist hier mit dem Beenden der Subshell mit gestorben.

Gleichzeitig belegt dieser Vorgang, dass die globale Variable B (Wert 22) in dieser Shell (PID 9458), trotz gleichem Bezeichner, eine andere globale Variable B ist, als die globale Variable B (Wert 44) der später initialisierten zweiten Shell (PID 9478). Für die lokale Variable a gilt dies ohnehin.

 

Ein weiteres Attribut, welches man einer Variablen mitgeben kann, ist die Eigenschaft nur gelesen werden zu können:

 

input
readonly variablenname

 

Dies wird oft bei Konstanten angewandt, deren Wert nicht verändert werden soll. Diese Eigenschaft wird auch bei Kopien globaler Variablen mit vererbt.

 

Für beide Eigenschaften (global und readonly) gibt es noch einen gemeinsamen Befehl, mit dem sich diese Attribute setzen lassen können. Der declare-Befehl. Zudem ist er der einzige Befehl, mit dem sich diese Attribute auch wieder zurücknehmen lassen können:

 

input
declare -x variablenname

 

...setzt Variable auf global.

 

input
declare +x variablenname

 

...entfernt das globale Attribut wieder.

 

input
declare -r variablenname

 

...setzt Variable auf readonly.

 

input
declare +r variablenname

 

...entfernt das readonly Attribut wieder.

 

Etwas verwunderlich ist hier sicher die Tatsache, dass Attribute mit - gesetzt und mit + entnommen werden. Aber so ist es nunmal.

 

Schließlich benötigt man noch einen Befehl, mit dem sich Variablen bei Bedarf auch vollständig löschen lassen. Dazu verwendet man den unset-Befehl:

 

input
unset variablenname

 

Damit wird eine Variable und deren Inhalt vollständig zerstört.

 

Das Betriebssystem kennt bereits einige globalen Variablen, welche deshalb auch oft Systemvariablen genannt werden. Obwohl einigen dieser Variablen direkt andere Werte zugewiesen werden könnten, sollte man dies nicht durchführen, da sie von den meisten Programmen ausgewertet werden. Andere dieser Variablen hingegen kann man gar nicht erst (direkt) einen neuen Wert zuweisen.

Im Folgenden eine kleine Übersicht einiger Systemvariablen und ob sie direkt veränderbar sind:

 

Variable veränderbar Bedeutung
$HOME
Heimatverzeichnis des Benutzers
$USER
Anmeldename des Benutzers
$PPID
Prozess-ID des Muterprozesses
$LANG
verwendete Zeichenkodierung des Benutzers (z.B. UTF-8)
$PATH
Suchpfad für ausführbare Programme des Benutzers
$* x
Parameterliste, übergeben an ein Programm
$# x
Anzahl der übergebenen Parameter
$0 x
Name des ausführenden Scripts
$1 bis $9
x
übergebene Parameter 1 bis 9
$? x
Rückgabewert des letzten Prozesses
$! x
Prozess ID des letzten Hintergrundprozesses
$$ x
Prozess ID der aktuellen Shell

 

 

Auch innerhalb eines Scripts wird zwischen globalen und lokalen Variablen differenziert. Dabei bezieht sich deren Wirkungsbereich nur auf das Programm selbst, weshalb sie auch globale und lokale Programmvariablen genannt werden. Im Gegensatz zu vielen anderen Programmiersprachen sind Variablen innerhalb von Shellscripten erstmal an jeder Stelle global. Auch innerhalb von Funktionen. Dazu ein Beispiel eines Scripts zu Primzahlberechnung (die genau Arbeitsweise soll an dieser Stelle nicht interessieren):

 

example
#!/bin/bash

CEILING=10000   # 1 to 10000
PRIME=0
E_NOTPRIME=

is_prime ()
{
  local factors
  factors=( $(factor $1) )  # Load output of `factor` into array.

if [ -z "${factors[2]}" ]
then
  return $PRIME             # 0
else
  return $E_NOTPRIME        # null
fi
}

echo
for n in $(seq $CEILING)
do
  if is_prime $n
  then
    printf %5d $n
  fi   #    ^  Five positions per number suffices.
done   #       For a higher $CEILING, adjust upward, as necessary.

echo

exit

 

Dieses Script initialisiert zu Beginn die drei globalen Programmvariablen CEILING, PRIME und E_NOTPRIME fest. Eine Eigenschaft die jetzt schon erkennbar ist und sich mit den globalen Systemvariablen deckt ist, dass alle Buchstaben groß geschrieben werden. Dies ist keine Pflicht, aber eine konforme Notation. So kann man sie auch im weiteren Programmverlauf schnell als globale Programmvariablen identifizieren.

Innerhalb der Funktion is_prime () wird die Variable factors initialisiert. Vor dem Variablennamen steht das Schlüsselwort local. Dieses Schlüsselwort definiert eine darauf folgende Variable als lokale Programmvariable. Damit besitzt sie ihre Gültigkeit nur innerhalb und für die Dauer der Funktion is_prime (). Ist die Funktion abgearbeitet, existieren weder die Variable factors, noch deren Inhalt. Allein schon deshalb kann außerhalb der Funktion is_prime () gar nicht mehr auf die lokale Programmvariable factors zugegriffen werden.

Weiterhin ist zu erkennen, dass innerhalb der Funktion is_prime () aber auf die globalen Programmvariablen zugegriffen werden kann. Hier bei den Rückgabewerten return $PRIME und return $E_NOTPRIME.Daher kommt auch der Begriff globale Programmvariable. Auf diese Variablen kann aus jeder Stelle im Programmcode aus zugegriffen werden.

 

Zuletzt aktualisiert am Samstag, den 24. Oktober 2009 um 23:30 Uhr