Shell-Workshop (3)

Status
Für weitere Antworten geschlossen.

itari

Benutzer
Mitglied seit
15. Mai 2008
Beiträge
21.900
Punkte für Reaktionen
14
Punkte
0
In diesem Workshop geht es um die Ausführungslogik von Kommandos.

Die Programmierer der Kommandos und Tools haben eine Möglichkeit der aufrufenden Shell mitzuteilen, ob sie erfolgreich ausgeführt worden sind. Das geht über eine interne Variable, den exit-Status '$?'. Üblicherweise ist dieser '0', wenn alles zufriedenstellend gelaufen ist und er ist ungleich '0', z. B. '1', wenn eine fehlerhafte Bearbeitung signalisiert werden soll. Das Kommando 'echo' kann unmittelbar nach der Ausführung zur Anzeige des exit-Status verwendet werden:

Rich (BBCode):
Syno> pwd
/root
Syno> echo $?
0
Syno>

Ruft man ein Kommando auf, dass es nicht gibt oder dass nicht ausführbar ist, dann schreibt die Shell selbst den exit-Status für den misslungenen Aufruf, und zwar wird dann oft der Wert 127 verwendet.

Es gibt nun einige Kommandos, die nur dazu da sind, einen exit-Status zu erzeugen: ':' bzw. 'true' und 'false':

Rich (BBCode):
Syno> :
Syno> echo $?
0
Syno> true
Syno> echo $?
0
Syno> false
Syno> echo $?
1
Syno>

Das Kommando ':' wird auch manchmal als das 'Null'-Kommando bezeichnet; es wird gelegentlich auch als eine Art Kommentar verwendet. Aber Vorsicht, es ist nicht identisch mit dem Kommentarzeichen '#', welche auf jeden Fall alles bis zum Zeilenende als Kommentar ignoriert.

In fast jeder Shell hat man nun die Möglichkeit, Kommandos aneinander zu reihen und kann dabei den Exit-Status als eine Art Wahrheitswert für eine logische Verarbeitung nutzen. Es gibt 3 einfache Reihungsoperatoren: ';' (sequence), '&&' (and) und '||' (or). Es gibt haufenweise Wikipedia-Beiträge zu diesem Thema; wer also was nachlesen will, der könnte z. B. hier anfangen.

Für uns ist wichtig, dass bei einer ';'-Verknüpfung der exit-Status keine Rolle spielt. Bei einer &&-Verknüpfung werden die Kommandos von links nach rechts ausgewertet und das nächste immer nur dann ausgeführt, wenn der exit-Status des aktuellen gleich '0' ist. Bei einer ||-Verknüpfung werden auch die Kommandos von links nach rechts ausgewertet und das nächste Kommando immer nur dann ausgeführt, wenn der exit-Status des aktuellen ungleich '0' ist.

Vor und hinter den Verknüpfungsoperatoren können, müssen aber nicht Leerstellen stehen. Meist macht man sie, damit es hübscher aussieht.
Rich (BBCode):
Syno> whoami;date
root
Tue Mar  8 08:18:49 CET 2011
Syno> whoami && date
root
Tue Mar  8 08:20:10 CET 2011
Syno> whoami || date
root
Syno> true && echo 'huhu'
huhu
Syno> false && echo 'huhu'
Syno> true || echo 'huhu'
Syno> false || echo 'huhu'
huhu
Syno>

Diese logischen Reihungsoperatoren kann man also z. B. dazu benutzen, Fehlermeldungen oder Erfolgsmeldungen auszugeben; oft werden diese nicht auf den Bildschirm gepostet, sondern in eine Protokolldatei wie die /var/log/messages.

Wie man sich sicherlich vorstellen kann, kann man auch mehr als 2 Kommandos mit solchen Operatoren zu einer Kommando-Kette verbinden. Der exit-Status der gesamten Kommandokette wird durch das letzte ausgeführte Kommando bestimmt.

Die Shell besitzt auch sogenannte Ablauf-Kontroll-Strukturen, die man durch den exit-Status steuern kann. Beispielhaft nehmen wir die 'if-then-[else]-fi'-Struktur:
Rich (BBCode):
Syno> if true
> then
> echo 'wahr'
> fi
wahr
Syno> if false
> then
> echo 'wahr'
> else
> echo 'unwahr'
> fi
unwahr
Syno>

Man kann zwischen 'then' und 'fi' im ersten Fall und zwischen 'then' und 'else' bzw. 'else' und 'fi' im zweiten Fall auch mehr als ein Kommando verwenden, so dass auch die Steuerung von Kommando-Blöcken möglich wird; das wird gerne in sogenannten 'Shell-Skripten' eingesetzt.

Die interaktive Eingabe auf jeweils neue Zeilen ist notwendig. Allerdings kann man dies durch einen Trick umgehen, indem man den Zeilenvorschub durch ein ';' ersetzt (';' = Reihungsoperator 'sequence'):

Rich (BBCode):
Syno> if true; then echo 'wahr'; fi
wahr
Syno>

Man darf eine if-Struktur auch in eine if-Struktur integrieren ...


=====
Alles klar? Viel Spaß beim Ausprobieren.

Itari



=========================================
Sinnvollerweise sind die Shell-Workshops aufeinander aufgebaut.

Shell-Workshop (2)
Shell-Workshop (4)
 
Zuletzt bearbeitet:

Binomico

Benutzer
Mitglied seit
01. Jun 2010
Beiträge
573
Punkte für Reaktionen
0
Punkte
0
Hi itari,

d.h. wenn ich in einem Shell-Script mehrere Kommandos hintereinander ausführen möchte und das jeweils folgende dann ausgeführt werden soll, wenn das vorherige erfolgreich war, muss ich ein || setzen? Oder besser doch mit if fi? Kannst du mir das anhand folgenden Beispiels erklären, da tu ich mir grad etwas schwer, diese zu verknüpfen (mom. rattert das Script von oben nach unten und erfüllt nur das erste Kommando - ich glaub der Bezug, auch der folgenden Kommandos, steht irgendwie nur auf das erste find, sprich find aktualisiert nicht nach dem ersten ausgeführten Befehl?!).

#!/bin/sh
#
# search for files with spaces and replace
find /volume1/Video/ -type f -name "* *" -print | while read file
do
new=`echo "$file" | sed 's/ /./g'`
mv "$file" "$new"
done
#
#
# search for folders with spaces and replace
find /volume1/Video/ -type d -name "* *" -print | while read file
do
new=`echo "$file" | sed 's/ /./g'`
mv "$file" "$new"
done
#
# search for files with minus and replace
find /volume1/Video/ -type f -name "*-*" -print | while read file
do
new=`echo "$file" | sed 's/-/./g'`
mv "$file" "$new"
done
#

Gruß
 

itari

Benutzer
Mitglied seit
15. Mai 2008
Beiträge
21.900
Punkte für Reaktionen
14
Punkte
0
d.h. wenn ich in einem Shell-Script mehrere Kommandos hintereinander ausführen möchte und das jeweils folgende dann ausgeführt werden soll, wenn das vorherige erfolgreich war, muss ich ein || setzen?

cmd1 || cmd2 || cmd3 => wenn cmd1 erfolgreich, dann hörts auf. (true OR true/false OR true/false <=> true) Dahinter steckt die Erkenntnis: Wenn der erste exit-Wert true ist bei einer OR-Verknüpfung kann abgebrochen werden, weil sich der Wahrheitswert der Gesamtaussage nicht mehr ändern würde.

cmd1 && cmd2 && cmd3 => wenn cmd1 daneben geht, dann hörts auf, ansonsten wird weiter gemacht. (false AND true/false AND true/false <=> false) - Das '&&' wäre also das, was du brauchst!

Ich weiss, dass das dies nicht ganz einfach Kost ist. Deswegen am besten mit 'einfachen' Beispielen üben. Um dein Skript 'hübscher' zu machen und um eine solche Logik einfach einzubauen, so dass man sie auch sofort sieht, bräuchte man die verhübschenden Shell-Funktionen. Ansonsten wäre das irgendwie etwas unübersichtlich. Darf ich deswegen das Beispiel etwas zurückstellen?

Itari
 

Binomico

Benutzer
Mitglied seit
01. Jun 2010
Beiträge
573
Punkte für Reaktionen
0
Punkte
0

itari

Benutzer
Mitglied seit
15. Mai 2008
Beiträge
21.900
Punkte für Reaktionen
14
Punkte
0

Binomico

Benutzer
Mitglied seit
01. Jun 2010
Beiträge
573
Punkte für Reaktionen
0
Punkte
0
Hi itari,

dein vorgelegtes Tempo überfährt mich :D ... aber ... it seems to work fine!

Danke *zwinker*

Grüße
 
Status
Für weitere Antworten geschlossen.
 

Kaffeautomat

Wenn du das Forum hilfreich findest oder uns unterstützen möchtest, dann gib uns doch einfach einen Kaffee aus.

Als Dankeschön schalten wir deinen Account werbefrei.

:coffee:

Hier gehts zum Kaffeeautomat