Diese Seite ist optimiert für eine Auflösung von min. 1280x1024.

facebook   google   twitter   digg   email  





Bash-Schleifen



Der test-Befehl


Wer bereits PHP, Perl oder "sonstwas" Programmiert hat, dem ist die if-Abfrage ein Begriff. Mittels der if-/else-Abfrage kann man einen Wert auf seinen Inhalt hin prüfen und veranlassen, was eintreten soll, wenn eine Situation eintritt - oder eben nicht. Ein sehr praxisnahes Beispiel dazu: "Ist die Anzahl der Äpfel mehr als 4 verschenke alles was mehr ist, ansonsten behalte die Äpfel und verschenke nichts." Eine typische if-/else-Abfrage (wenn - dann). Die Variable Apfel enthält also die Anzahl und muss getestet werden auf den Inhalt, also die Anzahl. Das erledigt der Befehl test. Dieser prüft auf Wahrheit hin und beendet sich mit einem "Errorcode". 0 ist dabei true und 1 ist false. Abfragen kann man diesen mit der Variable $? (Siehe TutorialBashvariabeln). Ein Beispiel:
pux@onkelpeter:~$ test 1 = 1
pux@onkelpeter:~$ echo $?
0
pux@onkelpeter:~$ test 1 = 2
pux@onkelpeter:~$ echo $?
1
pux@onkelpeter:~$ 
Der Befehl test hat viele verschiedene Möglichkeiten zum testen. das "=" ist dabei noch das "langweiligste". In der man-Page zu test findet man dazu alle verfügbare Parameter. Um nun etwas "Programmier-Style" zu wahren, gibt es noch den Befehl [, der in der oft ein Alias auf test ist. Ist er das nicht, macht er aber dennoch das gleiche:
pux@onkelpeter:~$ [ 1 = 2 ]
pux@onkelpeter:~$ echo $?
1
pux@onkelpeter:~$ 
Wichtig sind die Leerzeichen zwischen den eckigen Klammern und den Werten (da so ne Klammer ja ein Befehl ist würde die Bash das zusammengeschriebene einfach nicht finden können und einen Fehler ausspucken - logisch, wa? ;-)).

if-/else-Abfragen und wie man ein Script daraus macht

Um nun wirklich mit dem test-Befehl arbeiten zu können, bietet sich if und else an. Bleiben wir bei den Äpfeln von vorhin. Das würde dann so aussehen:
APFEL="5";
if [ "$APFEL" -ge "3" ]; then
   echo "Wir haben mehr als 3 Apfels, auf zum verschenken...";
else
   echo "Schnell weg, bevor jemand nen Appel will...";
fi;
Das "kann" man so auf der shell tippen, will man aber nicht. Deswegen packt man das alles in eine Datei script.sh rein, macht ein chmod 755 script.sh, schreibt noch ein shebang rein und schon kann man das komfortabler machen:
#!/bin/bash
APFEL="5";
if [ "$APFEL" -ge "3" ]; then
   echo "Wir haben mehr als 3 Apfels, auf zum verschenken...";
else
   echo "Schnell weg, bevor jemand nen Appel will...";
fi;
Als shebang bezeichnet man die erste Zeile, in der das "#!/bin/bash" steht. Es zeigt der Bash, welches Progeamm dieses Script ausführen soll. Bei einem Perl-Script (das über die Bash aufgerufen wird mit z.B. ./script.pl) steht dann am Anfang "#!/bin/perl". Man erinnere sich auch noch in diesem zusammenhand an die PATH-Variable, in der der aktuelle Pfad nicht vorkommt. Das ist auch der Grund, warum ein script.sh die Meldung "bash: script.sh: command not found" auswirft. Man muss den Pfad zum Script angeben. Ob absolut (/home/pux/script.sh) oder ob relativ (./script.sh) ist dabei egal.
Ahja; für die Fanatiker; man kann das wirklich alles in einer Shell eintippen:
pux@onkelpeter:~$ APFEL="5"; if [ "$APFEL" -ge "3" ]; then echo "Wir haben mehr als 3 Apfels, auf zum verschenken..."; else echo "Schnell weg, bevor jemand nen Appel will..."; fi;
Wir haben mehr als 3 Apfels, auf zum verschenken...
pux@onkelpeter:~$ 

subshells

Nun kann man ja damit schon einigen Unfug treiben. Wie aber kann man Werte, die man erst "später" kennt, da mit einbauen? Zum Beispiel will man einen Cronjob schreiben, der ein Backup eines Ordners macht wobei der Name der Backupdatei dann das Datum beinhalten soll. Realisieren kann man das so:
pux@onkelpeter:~$ tar cz ordner > backup_`date +%Y-%m-%d`.tar.gz
pux@onkelpeter:~$ 
Ein klassischer Fall für eine Subshell. Subshell bedeudet in etwa, dass ein Befehl ausgeführt wird in einer "untershell" um an ein Ergebnis zu gelangen. Ssh-Agents öffnet man z.B. auch in solch einer subshell: eval `ssh-agent`. Es gibt mehrere Formen dieser subshells. eine davon (siehe oben) besteht darin, sogenannte Backticks zu verwenden, eine Andere schaut so hier aus: $(date +%Y-%m-%d).

if-/else-Abfragen Extented

Es gibt auch noch die elseif-Abfragen. Diese braucht man z.B. für folgendes Konstrukt. Wenn ich mehr als 3 Äpfel habe, verschenke sie, aber wenn es mehr als 10 sind, schicke mir erstmal ne mail, weil ich die dann persönlich verteilen will:
APFEL="3";
if [ "$APFEL" -le "3" ]; then
   echo "weniger als 3 apfels, eigenen obstsalat machen";
elif [ "$APFEL" -ge "10" ]; then
   echo "mehr als 10 apfels, erstmal abwarten";
   echo "wir haben mehr als 10 apfels, wem spenden wir die?" | mail -s 'apfelscript'
else
   echo "mehr als 3 apfels aber weniger als 10 apfels, also verteilen gehen";
fi;

for-Schleifen

In unserem Bereich kommt man um for-Schleifen eigentlich nicht drumherum. Man braucht sie ständig und das nicht zum Programmieren, sondern wirklich zum normalen arbeiten. for-Schleifen arbeiten nach dem Prinzip "Für jeden übergebenen Wert führe diese Schleife einmal aus". Um ein schnelles Beispiel zu schustern: Du sollst auf allen server-Servern von 1 bis 30 die load ermitteln. Nun kannste das von Hand machen, oder eben nicht.
for i in `seq 1 30`; do
   echo "server$i hat folgende Load";
   ssh server$i 'uptime';
done;
Das ist dann schon eher die Script-Syntax, die zum Verständnis so einfach besser zum lesen ist. Jedoch auf der Kommandozeile haut man das alles in eine Zeile :-).
pux@onkelpeter:~$ time for i in `seq 1 30`; do echo "server$i hat folgende Load"; ssh server$i 'uptime'; done;
server1 hat folgende Load
 14:12:34 up 42 days, 10:49,  1 user,  load average: 2.12, 2.82, 3.31
server2 hat folgende Load
 14:12:34 up 42 days, 10:44,  0 users,  load average: 3.00, 1.85, 1.41
server3 hat folgende Load
 14:12:34 up 45 days,  4:40,  0 users,  load average: 1.58, 2.19, 2.62
server4 hat folgende Load
 14:12:34 up 42 days, 10:41,  0 users,  load average: 1.77, 2.02, 1.84
[...]
server29 hat folgende Load
 14:12:43 up 42 days, 10:07,  0 users,  load average: 2.81, 3.76, 4.04
server30 hat folgende Load
 14:12:43 up 42 days, 10:03,  0 users,  load average: 1.30, 1.47, 1.65

real   0m9.280s
user   0m0.300s
sys   0m0.080s
pux@onkelpeter:~$ 
Das alles also in 9 Sekunden. Von Hand wird es so schnell sicherlich nicht gehen. Auch eine Möglichkeit, wenn die zu bearbeitenden Hosts in einer Datei stehen:
pux@onkelpeter:~$ cat mooh 
server22
server13
server43
server65
server86
pux@onkelpeter:~$ time for i in `cat mooh`; do echo "$i hat folgende Load"; ssh $i 'uptime'; done;
server22 hat folgende Load
 14:15:30 up 54 days, 23:55,  1 user,  load average: 5.33, 5.63, 6.60
server13 hat folgende Load
 14:15:30 up 49 days, 23:40,  1 user,  load average: 8.34, 9.85, 12.58
server43 hat folgende Load
 14:15:30 up 42 days,  9:37,  1 user,  load average: 5.49, 7.38, 8.07
server65 hat folgende Load
 14:15:31 up 9 days, 13:32,  0 users,  load average: 3.43, 3.89, 4.16
server86 hat folgende Load
 14:15:31 up 42 days,  8:16,  0 users,  load average: 7.28, 7.95, 6.42

real   0m1.264s
user   0m0.052s
sys   0m0.016s
pux@onkelpeter:~$ 

while-Schleifen

While-Schleifen funktionieren von der Syntax her wie for-Schleifen. Ich benutze sowas gerne für z.B. "unendliche" Schleifen.
while /bin/true; do
echo "Schleife laueft";
sleep 3;
done;
case-Abfragen
Case Abfragen werden häufig in Menüs benutzt, wenn eine Variable verschiedene Inhalte haben kann, aber diese fest definiert sind. Z.B.:
menuitem="2";
case $menuitem in
        0) echo "option 0";;
        1) echo "option 1";;
        2) echo "option 2";;
        3) echo "option 3";;
        4) echo "option 4";;
esac



  logo