Kapitel 9 Nützliche Funktionen
Dieses Kapitel zeigt Ihnen einige sehr hilfreiche »Funktionen«, auf die bisher noch nicht eingegangen werden konnte. Natürlich stellt dies noch lange nicht den kompletten Funktionsumfang der Shell-Funktionen dar, weshalb Sie neben der Linux-UNIX-Kommandoreferenz (Kapitel 14) in diesem Buch im Anhang noch einen Überblick zu allen »Builtins« für die jeweilige Shell finden.
9.1 Der Befehl eval
Ein auf den ersten Blick etwas ungewöhnliches Kommando lautet eval. Die Syntax:
eval Kommandozeile
Mit eval können Sie Kommandos ausführen, als würden Sie diese in der Kommandozeile von Tastatur eingeben. Schreiben Sie eval vor einem Kommando in die Kommandozeile, wird das Kommando oder die Kommandofolge zweimal ausgeführt. Im Fall einer einfachen Kommandoausführung oder -folge ohne eval ist eine doppelte Bewertung nicht sinnvoll:
you@host > eval ls -l | sort -r
...
Anders hingegen sieht dies aus, wenn Sie eine Befehlsfolge in einer Variablen abspeichern wollen, um diese daraufhin ausführen zu lassen:
you@host > LSSORT="ls -l | sort -r"
you@host > $LSSORT
ls: |: Datei oder Verzeichnis nicht gefunden
ls: sort: Datei oder Verzeichnis nicht gefunden
Sicherlich haben Sie etwas Derartiges schon einmal ausprobiert. Wollen Sie die Befehlsfolge, die Sie in der Variablen LSSORT gespeichert haben, jetzt ausführen, ist das Kommando eval erforderlich. Die anschließende Fehlermeldung sagt alles. Verwenden Sie hier am besten mal set –x und sehen Sie sich an, was die Shell aus der Variablen $LSSORT macht:
you@host > set -x
you@host > $LSSORT
+ ls -l '|' sort -r
ls: |: Datei oder Verzeichnis nicht gefunden
ls: sort: Datei oder Verzeichnis nicht gefunden
Das Problem ist hierbei also das Pipe-Zeichen. Dieses müsste von der Shell ein zweites Mal bewertet werden, aber stattdessen wird die Befehlsfolge gleich ausgeführt, sodass hier das Pipe-Zeichen als Argument von ls bewertet wird. Sie können die Variable LSSORT drehen und wenden wie Sie wollen, die Shells verwenden grundsätzlich einen Ausdruck nur einmal. Hier greift eval mit seiner doppelten Ausführung ein:
you@host > eval $LSSORT
...
Schalten Sie wieder die Option –x ein, können Sie erkennen, dass mithilfe von eval die Variable LSSORT zweimal ausgeführt wird:
you@host > eval $LSSORT
+ eval ls -l '|' sort -r
++ /bin/ls -l
++ sort -r
...
eval eignet sich also in Shellscripts für die Ausführung von Kommandos, die nicht im Script enthalten sind, sondern erst während der Laufzeit des Scripts festgelegt werden. Sinnvoll ist dies beispielsweise, wenn Sie in Ihrem Script ein Kommando verwenden, das es auf einem bestimmten System nicht gibt. So können Sie dem etwas erfahreneren Anwender eine Möglichkeit geben, sich sein Kommando selbst zusammenzubasteln:
# Name: aeval
while true
do
printf "Kommando(s) : "
read
eval $REPLY
done
Das Script bei der Ausführung:
you@host > ./aeval
Kommando(s) : var=hallo
Kommando(s) : echo $var
hallo
Kommando(s) : who
you :0 Mar 30 14:45 (console)
Kommando(s) : echo `expr 5 + 11`
16
Kommando(s) : asdf
./script1: line 1: asdf: command not found
Kommando(s) : ps
PID TTY TIME CMD
3242 pts/41 00:00:00 bash
4719 pts/41 00:00:00 bash
4720 pts/41 00:00:00 ps
Kommando(s) : echo $$
4719
Kommando(s) : exit
you@host > echo $$
3242
Man könnte meinen, man hat eine eigene Shell vor sich.
Es gibt noch einen besonders überzeugenden Anwendungsfall von eval. Mit eval haben Sie die Möglichkeit, indirekt auf eine Variable zuzugreifen. Alte C–Fanatiker werden feuchte Augen bekommen, da sich das Ganze wie bei den Zeigern in C anhört. Das Prinzip ist eigentlich einfach, aber nicht gleich durchschaubar. Daher ein Beispiel:
# Name: aeval_cool
Mo=backup1
Di=backup2
Mi=backup3
Do=backup4
Fr=backup5
Sa=backup6
So=backup7
tag=`date +"%a"`
eval backup=\$$tag
echo "Heute wird das Backup-Script $backup ausgeführt"
./$backup
Das Script bei der Ausführung (an einem Mittwoch):
you@host > ./aeval_cool
Heute wird das Backup-Script backup3 ausgeführt
./backup3
Durch die Kommando-Substitution wurde veranlasst, dass sich in der Variable »tag« die ersten zwei Zeichen des Wochentags befinden. Im Beispiel war es Mittwoch, daher ist tag=Mi. Danach wird es ein wenig seltsam, aber durchaus logisch:
eval backup=\$$tag
Wollen Sie wissen, was da in den zwei Durchläufen passiert, verwenden Sie doch einfach wieder die Option –x:
set -x
eval backup=\$$tag
set +x
Ein erneuter Aufruf des Shellscripts:
you@host > ./aeval_cool
++ eval 'backup=$Mi'
+++ backup=backup3
...
Im ersten Durchlauf wird aus \$$tag die Zeichenfolge $Mi. Die Variable »Mi« hat ja den Wert »backup3«, was korrekterweise im zweiten Durchlauf an die Variable »backup« übergeben wird. Also wird im ersten Durchlauf der Ausdruck backup=\$$tag zu backup=$Mi. Die Zeichenfolge »Mi« hatten Sie ja zuvor aus der Kommando-Substitution erhalten. Anschließend durchläuft eval den Ausdruck backup=$Mi nochmals, sodass daraus backup=backup3 wird. Das erste Dollarzeichen wurde im ersten Durchlauf mit einem Backslash maskiert und somit vor einem Zugriff der Shell geschützt. Dadurch blieb im zweiten Durchlauf das Dollarzeichen bestehen, sodass hier tatsächlich eine Variable an eine andere Variable überwiesen wurde. Versuchen Sie doch einmal, das Ganze ohne eval-Anweisung so kurz und bündig zu gestalten.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.
|