8.6 Mehrere Scripts verbinden und ausführen (Kommunikation zwischen Scripts)
Im Laufe der Zeit werden Sie eine Menge Scripts schreiben und sammeln. Häufig will man hierbei gern das ein oder andere von einem anderen Script verwenden. Entweder man verwendet dann »Copy & Paste« oder man ruft das Script aus dem Haupt-Script auf. Da es nicht immer ganz einfach ist, Scripts miteinander zu verbinden und die Datenübertragung zu behandeln, soll im folgenden Abschnitt ein wenig genauer darauf eingegangen werden.
8.6.1 Datenübergabe zwischen Scripts
Zur Übergabe von Daten an das neue Script gibt es mehrere gängige Möglichkeiten. Eine einfache ist das Exportieren der Daten, bevor das zweite Script aufgerufen wird. Der Einfachheit halber werden wir hier von »script1« und »script2« reden und diese in der Praxis auch mehrmals verwenden. Hier die Möglichkeit, Daten an ein anderes Script mittels export zu übergeben:
# Name script1
a=1
b=2
c=3
export a b c
./script2
Jetzt das script2:
# Name : script2
echo "$0 : a=$a; b=$b; c=$c"
Die Datenübergabe bei der Ausführung:
you@host > ./script1
./script2 : a=1; b=2; c=3
Eine weitere Möglichkeit ist die Übergabe als Argument, wie Sie dies von der Kommandozeile her kennen. Dem aufgerufenen Script stehen dann die einzelnen Variablen mit den Positionsparametern $1 bis $9 bzw. ${n} zur Verfügung. Auch hierzu wieder die beiden Scripts.
# Name script1
a=1
b=2
c=3
./script2 $a $b $c
Und script2:
# Name : script2
echo "$0 : a=$1; b=$2; c=$3"
Die Ausführung entspricht der im Beispiel mittels export.
Sobald allerdings der Umfang der Daten zunimmt, werden Sie mit diesen beiden Möglichkeiten recht schnell an Grenzen stoßen. Hierzu würde sich die Verwendung einer temporären Datei anbieten: Ein Prozess schreibt etwas in die Datei und ein anderer liest wieder daraus.
# Name script1
IFS='\n'
for var in `ls -l`
do
echo $var
done > file.tmp
./script2
Das »script2«:
# Name : script2
while read line
do
echo $line
done < file.tmp
Im Beispiel liest »script1« zeilenweise von `ls –l` ein und lenkt die Standardausgabe von echo auf die temporäre Datei file.tmp um. Am Ende wird »script2« gestartet. »script2« wiederum liest zeilenweise über eine Umlenkung von der Datei file.tmp ein und gibt dies auch zeilenweise mit echo auf dem Bildschirm aus. Das Ganze könnten Sie auch ohne eine temporäre Datei erledigen, indem Sie beide Scripts mit einer Pipe starten, da hier ja ein Script die Daten auf die Standardausgabe ausgibt und ein anderes Script die Daten von der Standardeingabe erhält:
you@host > ./script1 | ./script2
Damit dies auch funktioniert, müssen Sie in den beiden Scripts lediglich die Umlenkungen und den Scriptaufruf entfernen. Somit sieht »script1« wie folgt aus:
# Name script1
IFS='\n'
for var in `ls -l`
do
echo $var
done
Und gleiches Bild bei »script2«:
# Name : script2
while read line
do
echo $line
done
8.6.2 Rückgabe von Daten an andere Scripts
Der gängigste Weg, Daten aus einem Script an ein anderes zurückzugeben, ist eigentlich die Kommando-Substitution. Ein simples Beispiel:
# Name : script1
var=`./script2`
echo "var=$var"
Und das »script2«:
# Name : script2
echo "Hallo script1"
»script1« bei der Ausführung:
you@host > ./script1
var=Hallo script1
Gleiches funktioniert auch, wenn das Script mehrere Werte zurückgibt. Hierzu würde sich etwa das Aufsplitten der Rückgabe mittels set anbieten:
# Name script1
var=`./script2`
set $var
echo "$1; $2; $3"
Jetzt noch »script2«:
# Name : script2
var1=wert1
var2=wert2
var3=wert3
echo $var1 $var2 $var3
»script1« bei der Ausführung:
you@host > ./script1
wert1; wert2; wert3
Sollten Sie allerdings nicht wissen, wie viele Werte ein Script zurückgibt, können Sie das Ganze auch in einer Schleife abarbeiten:
# Name script1
var=`./script2`
i=1
for wert in $var
do
echo "$i: $wert"
i=`expr $i + 1`
done
Trotzdem sollte man auch bedenken, dass mit steigendem Umfang der anfallenden Datenmenge auch hier nicht so vorgegangen werden kann. In einer Variablen Daten von mehreren Megabytes zu speichern, ist nicht mehr sehr sinnvoll. Hier bleibt Ihnen nur noch die Alternative, eine temporäre Datei zu verwenden, wie Sie sie schon in Abschnitt 8.6.2 verwendet haben. Allerdings besteht auch hier ein Problem, wenn bspw. »script1« die Daten aus der temporären Datei lesen will, die »script2« hineinschreibt, aber »script2« die Daten nur scheibchenweise oder eben permanent in die temporäre Datei hineinschreibt. Dann wäre eine Lösung mit einer Pipe die bessere Alternative. Auch hierzu müssten Sie nur »script1« verändern:
# Name script1
./script2 | while read wert
do
for val in $wert
do
echo "$val"
done
done
Named Pipe
Ein weiteres sehr interessantes Mittel zur Datenübertragung zwischen mehreren Scripts haben Sie in Abschnitt 5.6 mit der Named Pipe (FIFOs) kennen gelernt. Der Vor- bzw. auch Nachteil (je nach Anwendungsfall) ist hierbei, dass ein Prozess, der etwas in eine Pipe schreibt, so lange blockiert wird, bis auf der anderen Seite ein Prozess ist, der etwas daraus liest. Umgekehrt natürlich derselbe Fall. Ein typischer Anwendungsfall wäre ein so genannter Server, der Daten von beliebigen Clients, die ihm etwas durch die Pipe schicken, einliest:
# Name: PipeServer
mknod meine_pipe p
while true
do
# Wartet auf Daten aus der Pipe
read zeile < meine_pipe
echo $zeile
done
Statt einer Ausgabe auf dem Bildschirm können Sie mit diesem Server munter Daten von beliebig vielen anderen Scripts sammeln. Der Vorteil: Die anderen Scripts, die Daten in diese Pipe schicken, werden nicht blockiert, weil immer auf der anderen Seite des Rohrs der Server »PipeServer« darauf wartet.
8.6.3 Scripts synchronisieren
Spätestens, wenn Ihre Scripts dauerhaft laufen sollen, benötigen Sie eine Prozess-Synchronisation. Fallen hierbei dann mehr als zwei Scripts an und wird außerdem in eine Datei geschrieben und gelesen, haben Sie schnell Datensalat. Eine recht einfache und zuverlässige Synchronisation zweier oder auch mehrerer Scripts erreichen Sie bspw. mit den Signalen. Richten Sie hierzu einfach einen Signalhandler mit trap ein, der auf ein bestimmtes Signal reagiert und ein weiteres Script aufruft. Bspw.:
# Name: script1
trap './script2' SIGUSR1
while true
do
echo "Lese Daten ..."
sleep 5
echo "Starte script2 ..."
kill -SIGUSR1 $$
done
Und das »script2«:
# Name: script2
trap './script1' SIGUSR2
while true
do
echo "Schreibe Daten ..."
sleep 5
echo "Starte script1 ..."
kill -SIGUSR2 $$
done
Die Scripts bei der Ausführung:
you@host > ./script1
Lese Daten ...
Starte script2 ...
Schreibe Daten ...
Starte script1 ...
Lese Daten ...
Starte script2 ...
Schreibe Daten ...
Starte script1 ...
Lese Daten ...
Starte script2 ...
Schreibe Daten ...
Eine weitere Möglichkeit zur Synchronisation von Scripts besteht darin, eine Datei zu verwenden. Hierbei wird in einer Endlosschleife immer überprüft, ob eine bestimmte Bedingung erfüllt ist. Je nach Bedingung wird dann ein entsprechendes Script ausgeführt. Hierzu werden alle Scripts aus einem Haupt-Script gesteuert. Was Sie dabei alles überprüfen, bleibt Ihnen überlassen. Häufig verwendet werden die Existenz, das Alter, die Größe oder die Zugriffsrechte auf eine Datei. Eben alles, was sich mit dem Kommando test realisieren lässt. Natürlich sollten Sie in einem Haupt-Script weiterhin die Steuerung übernehmen. Ein Beispiel:
# Name: mainscript
FILE=tmpfile.tmp
rm $FILE
touch $FILE
while true
do
# Ist die Datei lesbar
if [ -r $FILE ]
then
echo "Datei wird gelesen ..."
sleep 1
#./script_zum_Lesen
# Freigeben zum Schreiben
chmod 0200 $FILE;
fi
if [ -w $FILE ]
then
echo "Datei ist bereit zum Schreiben ..."
sleep 1
#./script_zum_Shreiben
# Freigeben zum Lesen
chmod 0400 $FILE
fi
sleep 1
done
Hier wird in einer Endlosschleife immer überprüft, ob eine Datei lesbar oder schreibbar ist und dann eben entsprechende Aktionen ausgeführt. Selbiges könnten Sie übrigens auch ohne eine extra Datei mit einer globalen Variablen erledigen. Sie überprüfen in einer Endlosschleife ständig den Wert der globalen Variablen und führen entsprechende Aktionen aus. Nach der Ausführung einer Aktion verändern Sie die globale Variable so, dass eine weitere Aktion ausgeführt werden kann.
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.
|