Page 1



Was ist ein Shell Script?

Ein Shell Script ist eine Textdatei bestehend aus

Program- und Funktionsaufrufen

Shell internen Kontrollstrukturen

Variablenzuweisungen

Das schreiben von Shell Scripts verlangt Wissen über

Die Shell internen Kontrollstrukturen

möglichst viele Unix Programme und

deren Optionen


Wozu Shell Scripts?

Shell Scripts bieten die Moglichkeit schnell und einfach Aufgaben zu

Automatisieren. Man kann eine Shell auch als eine Programmierspra-

che verwenden. Jedoch unterscheiden sich Scripts von Programmen

in Sprachen wie C betrachtlich. Im Shell Script sind alle Systempro-

gramme direkt verwendbar. Es gibt nur einen Typ von Variablen.

Diese müssen nicht initialisiert werden. Hier ließe sich nun eine lan-

ge Liste von Unterschieden angeben, stattdessen sei nur Folgendes

gesagt: Shell Script eignen sich besonders gut um Aufgaben “quick

and dirty” zu lösen. Ein Systemadministrator, der vor einer größeren

Aufgabe steht - etwa der Erzeugung von 100 durchnummerierten Ac-

counts, wird in der Regel versuchen dies mit einem Script zu losen.

Wird die Aufgabe größer so gehen dieÜberlegungen in Richtung Perl

und letztlich zu einer Compilersprache. Shell Scripts sollte man nicht

verwenden wenn

die Geschwindigkeit des Programms eine große Rolle spielt.

komplizierte Aufgaben gelöst werden sollen, die ein stark struk-

turiertes Programmieren erfordern.

Sicherheitsmechanismen verwendet werden sollen.

viele Dateien gelesen und geschrieben werden sollen.

man ein GUI haben will - GUI’s are for wimps anyway.


Page 2

Verschiedene Shells

sh Bourne shell, die erste Unix Shell von S. R. Bourne

bash Bourne Again Shell, Standard auf Linux, von der FSF

csh Berkeley Unix C Shell, C-ahnliche Syntax, Standard auf BSD

tcsh TENEX C Shell, erweiterte csh

ksh Korn Shell, proprietare Shell von David Korn

pdksh Public Domain Korn Shell

rc Shell fur Plan 9-OS

es Erweiterbare Shell auf Basis von rc

zsh Z Shell von Paul Falstad

ash kleine, POSIX konforme Shell, /bin/sh auf NetBSD

esh Easy Shell, kleine, leicht bedienbare Shell

kiss Karels Interactive Simple Shell

lsh Shell mit DOS Kommandos fur Umsteiger

osh Operators Shell, mit erweiterten Sicherheitsmechanismen

sash Stand-alone Shell, braucht keine Libraries

psh Perl Shell, Perl Syntax


Die Shell unserer Wahl

Shells gibt es sehr viele. Die obige Aufstellung erhebt keinerlei An-

spruch auf Vollständigkeit. Die Bourne Shell (sh), benannt nach ihrem

Erfinder, ist die Mutter aller Shells auf Unix Systemen. Die Bourne

Shell bot schon zu Anfang fast alle Möglichkeiten der Programmie-

rung, die die bash heute bietet. Die interaktive Bedienung war al-

lerding nicht sehr bequem. Dieser Umstand führte zur Geburt der

csh. csh-Scripts folgen einer anderen Syntax, die der Programmier-

sprache C ähnlich ist, als sh-Scripts. Ein weiterer Meilenstein in der

Geschichte der Shells war die Korn Shell ksh, ebenfalls nach ihrem

Erfinder benannt. Diese war ein sehr erfolgreiches proprietares Pro-

dukt. Die bash ist der Versuch einer Zusammenmischung der Vorzüge

verschiedener Shells, wobei die Programmierung in einer erweiterten

sh-Syntax erfolgt.

Im weiteren werden wir unser Hauptaugenmerk auf die bash legen,

die heute wohl die meistverwendete Shell ist. Die meisten unserer

Konstruktionen werden allerdings ohne wieteres auch mit einer sh

funktionieren.


Die Login Shell

Nach dem Login landet man auf Unix

Systemen in einer Shell. Welche Shells auf

einem System als mögliche Login Shell

installiert sind steht in der Datei /etc/shells.

$ cat /etc/shells

Die Login Shell jedes Users steht in der Datei

/etc/passwd.

$ grep $USER /etc/passwd | cut -d : -f 7

Ändern kann man seine Login Shell mit dem

Befehl chsh (aka change shell). Die Standard

Login Shell auf Linux Systemen ist die bash.




Page 3

Ein Shell Script schreiben

Ein Shell Script ist eine Textdatei, die Kommandos enthält. Welchen

Texteditor man zur Erzeugung dieser Datei verwendet ist egal, aber...

http://www.thinkgeek.com/images/products/zoom/vi-emacs.jpg

Beginnt diese Textdatei mit der Zeichenfolge

#!/bin/bash

und wird die Datei ausführbar gemacht

$ chmod 755 Dateiname

so kann das Script direkt mit seinem Namen aufgerufen werden.

$ ./scriptname

Das Script wird dann Zeile fur Zeile, vom Interpretor, in unserem Fall

der bash, abgearbeitet. Im Unterschied dazu müssen Programme, die

in Compilersprachen geschrieben sind, erst kompiliert werden, bevor

sie ausgeführt werden konnen.

Wie in allen Programmiersprachen ist das Kommentieren eines Scripts

ein oft ignoriertes Merkmal guten Programmierstils. Zeilen die mit #

beginnen gelten als Kommentare und werden ignoriert.


Kommentare

Zeilen im Script, die mit # beginnen werden als

Kommentar gewertet und beim Ausführen

ignoriert.

# Kommentare koennen helfen die

# Lesbarkeit von Shell Scripts

# zu erhoehen.

Die einzige Ausnahme ist, wenn die ersten zwei

Zeichen des Scripts #! lauten und unmittelbar

nachher der Pfad des Interpreters steht. Dies

macht Script direkt ausfuhrbar und gilt für

beliebige Interpretersprachen.

#!/bin/bash

#!/bin/csh

#!/bin/sh

#!/usr/bin/perl


Hello World

Das obligate Hello World Programm ist als

Shell Script denkbar einfach. Folgender Text

soll in der Datei helloworld gespeichert sein.

#!/bin/bash

echo "hello world"

Ist es ein Shell Script?

$ file helloworld

Ausführbar machen mit

$ chmod 755 helloworld

und ausführen mit

$ ./helloworld


Page 4



Variablen

Variablennamen bestehen aus Buchstaben,

und Ziffern.

Zuweisung erfolgt über

$ VARIABLENNAME=wert

Auf den Wert zugreifen mit $

$ echo $VARIABLENNAME

Unterschiedliche Variablenarten mit

Beispielen

selbstdefinierte Variablen:

$FOO, $BAR, ...

systemweite Variablen:

$HOSTNAME, $HOSTTYPE, ...

built-in Variablen:

$1-$9, $PS1, $PATH, ...

Variablen exportieren

$ export VARIABLENNAME


Variablen

Variablenname bestehen aus Buchstaben, und Zahlen, wobei oft auf

Kleinbuchstaben verzichtet wird. Die Zuweisung eines Wertes funk-

tioniert folgendermaßen:

$ VARIABLENNAME=wert

Auf den Wert einer Variable greift man mit $VARIABLENNAME zu.

$ echo $VARIABLENNAME

unset nimmt einer Variable ihren Wert.

unset VARIABLENNAME

In Shell Scripts gibt es nur einen Variablentyp. Man unterscheidet

also nicht wie in anderen Programmiersprachen Integer-, Gleitkomma-

und Stringvariablen. Wenn ein Script davon abhangt, daß in einer

Variable ein Integerwert steht, so ist der Author dafür verantwortlich,

daß dem auch so ist. Variablen müssen nicht initialisiert werden. Dies

bereitet oft Probleme bei Tippfehlern. Folgendes Beispiel führt zu

keiner Fehlermeldung:

$ TEST=Legasthenie

$ echo $TSET

$

Der Befehl set gibt eine Liste, der von der bash gesetzten Variablen.

Unter Anderen befindet sich darunter die Variable PS1 die das Ausse-

hen des Prompts bestimmt. MS-DOS Nostalgiker könnten sich über

folgendes freuen:

$ PS1="C:\> "

C:\>


In Scripts sind vor allem die Variablen $1-$9 von großer Bedeutung.

Diese enthalten die an das Script übergebenen Parameter. Dazu fol-

gendes Beispiel, das in der ausführbaren Datei parameters gespeichert

sein soll:

#!/bin/bash

# Ausgabe des ersten Parameters

echo "Erster Parameter: $1"

# Ausgabe des zweiten Parameters

echo "Zweiter Parameter: $2"

Und das kommt dabei heraus:

$ ./parameters foo bar

Erster Parameter: foo

Zweiter Parameter: bar





Page 5



Subshells

Aus einer Shell kann man eine weitere Shell

starten, welche dann als Subshell der

ursprünglichen Shell bezeichnet wird.

$ bash

Die im Script enthaltenen Kommandos werden

in

einer Subshell ausgeführt, wenn das Script

mit

$ ./script [&] oder

$ bash script [&]

in der aktuellen Shell augeführt, wenn das

Script mit

$ . script oder

$ source script

gestartet wird, wobei das otionale & das Script

im Hintergrund startet.



Subshells, Variablen exportieren

Ein grundsätzliches Konzept des Unix Prozeßmanagments ist, daß

jeder Prozeß von einem Parentprozeß abstammt. Dieser Text entsteht

in einer Instanz des Editors vim. Ein Auszug aus der Ausgabe des

Kommandos pstree soll dieses Konzept verdeutlichen:

$ pstree

init-+-arpwatch

[...]

|-xdm-+-XF86_SVGA

|

-xdm---fvwm2-+-FvwmCommandS

|

|-xterm---bash---vim

[...]

[...]

Der Prozeß init ist “Ahne” aller Prozesse. Der Login Manager xdm

wartet auf Benutzerauthentifizierung und startet einen Windowma-

nager fvwm2, aus dem ein xterm gestartet wurde in dem eine bash

läuft, aus der ein vim gestartet wurde.

Eine Subshell ist eine Shell, die aus einer anderen gestartet wurde.

Ruft man ein Shell Script via

$ ./script oder

$ bash script

auf, so wird es in einer Subshell gestartet. Ruft man es via

$ . script oder

$ source script

auf, so werden die darin enthaltenen Befehle in der aktuellen Shell

ausgeführt.

Besonders beachten sollte man, daß die Verwendung von

Pipelines auch innerhalb eines Shell Scripts zu Subshells führt.

Dies ist wichtig, weil Variablenzuweisungen auf eine bash Instanz

beschränkt sind. Die Zuweisung kann in alle Subshells mit dem Befehl

export exportiert werden. Folgende Kommandoabfolgen sollen das

verdeutlichen, wobei man sich durch pstree -h einenUberblick über

die aktuelle Situation machen kann.



Page 6



$ # Test wird nicht exportieren

$ TEST=rose

$ echo $TEST

rose

$ bash

$ echo $TEST

$ TEST=eros

$ echo $TEST

eros

$ exit

exit

$ echo $TEST

rose

$ unset TEST

$ exit

$ # Test wird exportiert

$ TEST=rose

$ echo $TEST

rose

$ export TEST

$ bash

$ echo $TEST

rose

$ TEST=eros

$ echo $TEST

14

eros

$ exit

exit

$ echo $TEST

rose

$ unset TEST

$ exit


Setzt man also in der Shell eine Variable und startet dann ein Shell

Script, so ist diese Variable - so sie nicht exportiert wurde - im Script

nicht gesetzt.


Page 7



Spezielle Zeichen und Quoting

Leerzeichen <space> und Tabulatoren <tab> werden als Trennzeichen

verwendet. So werden im folgenden Beispiel das Kommando, die Op-

tionen und die Parameter eines Befehls durch Leerzeichen getrennt:

$ ls -l foo bar

Manchmal ist es erwünscht, einem Zeichen mit spezieller Bedeutung

diese zu nehmen. So kann ein Dateiname auch ein Leerzeichen enthal-

ten. Seit Microsofts Betriebsysteme über die 8.3 Namenskonvention

hinausgekommen sind tritt dieses Phänomen leider gehäuft auf. Als

Beispiel nehmen wir eine Datei mit dem Namen Mein Lied.mp3 an.

Versucht man diese in der Shell zu löschen und schreibt:

$ rm Mein Lied.mp3

so versucht die Shell zwei Dateien mit Namen Mein beziehungsweise

Lied.mp3 zu löschen. Um der Shell mitzuteilen, dass das Leerzeichen

in diesem Fall keine spezielle Bedeutung hat, verwendet man eine der

drei Quoting Methoden. Diese seien im Folgenden anhand unseres

Beispiels angeführt:

$ rm Mein\ Lied.mp3

$ rm ’Mein Lied.mp3’

$ rm "Mein Lied.mp3"

Der Backslash \ (escape character) hebt dabei die spezielle Bedeutung

des unmittelbar folgenden Zeichens auf. Auch wenn dieses Zeichen ein

newline”, also das Resultat des Betätigens der Return Taste ist. So-

wohl einfache ’’ (single quotes) als auch doppelte Anfuhrungszeichen

"" (double quotes) heben die spezielle Bedeutung der Zeichen dazwi-

schen auf, wobei dies bei den einfachen Anfuhrungszeichen fur alle

Zeichen gilt. Bei doppelten Anführungszeichen bleibt die spezielle

Bedeutung der Zeichen $, ’ und \ erhalten. Vergleiche die Ausgaben

folgender Kommandos:


$ TEST=rose

$ echo "In \$TEST steht \"$TEST\""

In $TEST steht "rose"

$ echo ’In \$TEST steht \"$TEST\"’

In \$TEST steht \"$TEST\"


Im weiteren werden wir noch des öfteren auf spezielle Zeichen stoßen.


Quoting

Quoting wird dazu benutzt, um bestimmten

Zeichen ihre spezielle Bedeutung zu nehmen.

Es gibt drei Moglichkeiten um zu quoten.

\

escape character

’’ single quotes

"" double quotes

Hat ein geistreicher Benutzer eine Datei unter

Mein Lied * E-Donkey.mp3” abgespeichert, so

kann man diese mit einer der folgenden Zeilen

löschen:

$ rm Mein\ Lied\ \*\ E-Donkey.mp3

$ rm "Mein Lied * E-Donkey.mp3"

Der escape character nimmt dem folgenden

Zeichen seine spezielle Bedeutung. Alle Zeichen

zwischen single quotes sind von ihrer speziellen

Bedeutung befreit. Double quotes lassen den

Zeichen $, ’ und \ ihre spezielle Bedeutung.

Double quotes sind also schwächer als single

quotes.



Page 8


Befehle zu Gruppen zusammenfassen

Befehle werden durch einen Zeilenumbruch <newline> oder ein Se-

mikolon ; getrennt. Im folgenden zwei Schreibweisen, die das gleiche

liefern:

$ cd /usr/bin

$ ls

bzw.

$ cd /usr/bin; ls

Es gibt zwei Möglichkeiten, Kommandos zu Gruppieren. Runde Klam-

mern () (parantheses) beziehungsweise geschwungene Klammern {}

(curly braces). Befehle die in runden Klammern gruppiert sind, wer-

den in einer Subshell ausgeführt, während in geschwungenen Klam-

mern gruppierte Befehle in der aktuellen Shell ausgeführt werden.

Dazu folgende Beispiele:

$ { FOO=bar; echo "$FOO ist $FOO"; }; echo "$FOO ist $FOO"

$FOO ist bar

$FOO ist bar

$ ( FOO=bar; echo "$FOO ist $FOO" ); echo "$FOO ist $FOO"

$FOO ist bar

$FOO ist

Die runden und die geschwungenen Klammern zählen zu den spezi-

ellen Zeichen. Diese müssen also, so sie im Dateinamen auftreten, mit

Quotes versehen werden.


Kommandos Gruppieren

; Trennt verschiedene Kommandos, die in der

gleichen Zeile geschrieben werden. Die

Kommandos werden hintereinander

ausgeführt

() Ein oder mehrere Kommandos innerhalb

runder Klammern werden in einer Subshell

ausgeführt.

{} Ein oder mehrere Kommandos innerhalb

geschwungener Klammern werden als Block

in der aktuellen Shell ausgefuhrt.


Page 9


Wild Cards und Pattern Matching

Gehen wir im Folgenden davon aus, dass im aktuellen Verzeichnis

folgende Dateien existieren:

$ ls

glut gut hut mut mutter

* steht fur beliebige Zeichenketten; auch leere.

$ ls mut*

mut mutter

? steht fur genau ein beliebiges Zeichen.

$ ls ?ut

gut hut mut

Alle in eckigen Klammern angegebenen Zeichen dürfen anstelle der

eckigen Klammern vorkommen.

$ ls [gh]ut

gut hut

Ein ! oder ^ verneint diese Auswahl.

$ ls [!gh]ut

mut

Alle in geschwungenen Klammern angegebenen Zeichenketten, die

durch Beistriche getrennt sind, dürfen vorkommen,

$ ls {gl,m}ut

glut mut

Diese Konstrukte sind auch kombinierbar.

$ ls {gl,m}ut*

glut mut mutter



Wildcards und Pattern Matching

Folgende Zeichen haben in der Bash spezielle

Bedeutung

*

beliebige Zeichenkette

?

genau ein beliebiges Zeichen

[ ]

genau eines der genannten Zeichen

[^ ]

genau ein nicht genanntes Zeichen

oder [! ]

{ , }

genau eine der Zeichenketten