Eine kurze Einführung in wichtige Unix-Werkzeuge

Werbung
Eine kurze Einführung in
wichtige Unix-Werkzeuge
Shell, Make & Co.
Übungen zu Informatik B
(Objekt-orientierte Programmierung)
Elmar Ludwig
Universität Osnabrück
Sommersemester 2002
Inhaltsverzeichnis
1
Einführung in Unix-Werkzeuge
2
1.1
Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.1.1
Begriffe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
1.2
Terminal-Kontrolle . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
1.3
Unix-Manual Konventionen . . . . . . . . . . . . . . . . . . . . . . .
5
1.4
Typische Kommandos . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
1.5
Shell-Programmierung . . . . . . . . . . . . . . . . . . . . . . . . . .
8
1.5.1
Was ist ein Kommando? . . . . . . . . . . . . . . . . . . . . .
8
1.5.2
Was ist ein Wort? . . . . . . . . . . . . . . . . . . . . . . . . .
8
1.5.3
Textersatz für Variablen . . . . . . . . . . . . . . . . . . . . .
9
1.5.4
Textersatz für Kommandos . . . . . . . . . . . . . . . . . . . .
11
1.5.5
Arithmetik mit Variablen . . . . . . . . . . . . . . . . . . . . .
11
1.5.6
Textersatz für Argumente . . . . . . . . . . . . . . . . . . . . .
12
1.5.7
Dateinamen . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.5.8
Muster für Dateinamen . . . . . . . . . . . . . . . . . . . . . .
13
1.5.9
Ein-/Ausgabe-Umlenkung . . . . . . . . . . . . . . . . . . . .
13
1.5.10 Zusammengesetzte Kommandos . . . . . . . . . . . . . . . . .
14
1.5.11 Kontrollstrukturen . . . . . . . . . . . . . . . . . . . . . . . .
15
1.5.12 Eingebaute Kommandos . . . . . . . . . . . . . . . . . . . . .
17
Make . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
1.6
1
Kapitel 1
Einführung in Unix-Werkzeuge
Dies ist eine kurze Einführung in die wichtigsten Unix-Werkzeuge, die zur Programmentwicklung oder zur Bearbeitung von Textdokumenten nützlich sind. Die Übersicht
hier ist in vielen Bereichen unvollständig und vereinfacht, und ist daher als Referenzhandbuch nur sehr eingeschränkt zu empfehlen. Teile des Textes sind aus [ATS 94]
übernommen. Ein gutes Nachschlagewerk ist [Kernighan 84].
1.1
Motivation
Eine scheinbar einfache Problemstellung:
Wie wandle ich alle GIF-Bilder in meinem Heimatkatalog in das JPEG-Format um?
Lösung 1: Schreibe ein Programm zur Lösung dieser Speziellen Aufgabe.
Was ist, wenn nicht alle Bilder interessant sind?
Was ist, wenn ich PNG-Format haben möchte?
Was ist, wenn die Bilder auch noch verkleiner werden sollen?
Lösung 2: Stecke fertige „Programm-Komponenten“ aus einem „Baukasten“ so
zusammen, daß sie das Problem lösen.
Welche „Bausteine“ braucht man dafür?
– Finden und auswählen von Dateinamen (find)
– Erzeugung eines Namens für die Ausgabedatei (sed)
– Umwandeln eines Bildes in ein anderes Format (convert)
Was mache ich, wenn es keinen fertigen „Baustein“ gibt?
2
Lösung 2 ist natürlich wesentlich flexibler:
Bausteine können nahezu beliebig kombiniert werden.
Einfache Programm-Komponenten sind leichter zu implementieren, zu testen und
wiederzuverwenden.
Ein Werkzeug sollte eine kleine, klar definierte Aufgabe optimal erfüllen.
Eine Lösung könnte dann z.B. folgendermaßen aussehen:
for file in $(find /home/elmar -name "*.gif")
do
output=$(echo $file | sed s/gif$/jpeg/)
convert $file $output
done
1.1.1
Begriffe
Teminal
Gerät zur Ein- und Ausgabe von Text an einem Computer, heute meistens in Software emuliert (Terminal-Emulation).
Kommando
Anweisung an den Rechner, eine (Folge von) Operation(en) auszuführen.
Shell
Interaktives Interpreter-Programm für die Eingabe von Kommandos (im Dialog
mit dem Benutzer).
Prozeß
Ausführung eines Programms in einem Rechner.
Standard-Eingabe
Jeder Prozeß besitzt standardmäßig einen Eingabekanal (System.in)
Standard-Ausgabe
Jeder Prozeß besitzt standardmäßig einen Ausgabekanal (System.out)
Standard-Fehlerausgabe
Jeder Prozeß besitzt standardmäßig einen Ausgabekanal für Fehlermeldungen
(System.err)
3
1.2
Terminal-Kontrolle
Früher wurde ein Rechner von einem separaten Terminal aus benutzt, das über eine
serielle Schnittstelle angeschlossen war. Heute ist am PC oder an der Workstation der
Bildschirminhalt meistens direkt im Hauptspeicher und wir verwenden ein Programm
zur Terminal-Emulation, aber es gibt nach wie vor serielle Anschlüsse für Modems oder
an Terminal-Servern.
Kommandos ruft man zunächst im Dialog auf. Dazu hat man entweder ein Terminal oder
ein Fenster mit einer Terminal-Emulation. Letztlich holt das Betriebssystem Zeichen
von der Tastatur ab und schreibt Zeichen auf den Bildschirm. Eine Shell, das heißt,
ein Kommando-Interpreter, liest Zeilen und führt die darin beschriebenen Kommandos
meistens als eigene Prozesse aus.
Normalerweise kann man voraustippen und auch eine Zeile noch korrigieren, bevor sie
ein Prozeß sieht. Bestimmte Tasten haben dabei meistens eine besondere Bedeutung,
die über das Kommando stty gesteuert werden kann:
Taste
Delete (^?)
Ctrl-W (^W)
Ctrl-U (^U)
Ctrl-D (^D)
Ctrl-C
(^C)
Ctrl- (^\)
Ctrl-Z (^Z)
Ctrl-S (^S)
Ctrl-Q (^Q)
Name
erase
werase
kill
eof
intr
quit
susp
stop
start
Bedeutung
löscht vorhergehendes Zeichen in der gleichen Zeile
löscht vorhergehendes Wort in der gleichen Zeile
löscht alle vorhergehenden Zeichen in der gleichen Zeile
signalisiert Ende der Eingabe
schickt Interrupt-Signal an Prozeß
schickt Quit-Signal an Prozeß
hält den Prozeß an (weiter mit fg oder bg)
hält die Terminal-Ausgabe an
setzt die Terminal-Ausgabe fort
4
1.3
Unix-Manual Konventionen
Das man-Kommando liefert Informationen über Programme aus dem online-Manual.
Es gibt darin (unter anderem) Dokumentation zu allen Shell-Kommandos (ls, cp, rm,
mv, mkdir, gzip etc.).
Die Beschreibungen verwenden eine vorgegebene, feste Schablone (NAME ,
DESCRIPTION , EXAMPLES , SEE ALSO , . . . ):
SYNOPSIS ,
$ man column
COLUMN(1)
System Reference Manual
COLUMN(1)
NAME
column - columnate lists
SYNOPSIS
column [-tx] [-c columns] [-s sep] [file ...]
DESCRIPTION
The column utility formats its input into multiple
columns. Rows are filled before columns. Input is
taken from file operands, or, by default, from the
standard input. Empty lines are ignored.
The options are as follows:
-c
Output is formatted for a display columns wide.
-s
Specify a set of characters to be used to
delimit columns for the -t option.
-t
Determine the number of columns the input contains and create a table. Columns are delimited
with whitespace, by default, or with the characters supplied using the -s option. Useful for
pretty-printing displays.
-x
Fill columns before filling rows.
Column exits 0 on success, >0 if an error occurred.
5
ENVIRONMENT
COLUMNS
The environment variable COLUMNS is used to
determine the size of the screen if no other
information is available.
EXAMPLES
ls -l | sed 1d | column -t
SEE ALSO
colrm(1),
ls(1),
paste(1),
sort(1)
HISTORY
The column command appeared in 4.3BSD-Reno.
BSD Experimental
June 6, 1993
1
Die Syntax der SYNOPSIS-Zeile ist an BNF angelehnt und auch „so ähnlich“ zu lesen:
Worte in [. . . ] sind optional.
Alternativen werden mit | getrennt.
[-tx] ist hier aber eine Abkürzung für [-t] [-x].
Optionen (Schalter) stehen stets vor Dateinamen, die Reihenfolge der Optionen
ist aber beliebig. BNF kann das nicht einfach ausdrücken.
Optionen können kombiniert werden:
-tx
bedeutet -t -x
-c80
bedeutet -c 80
-xtc80 bedeutet -t -x -c 80
-- beendet die Optionen und wird ignoriert.
- beendet die Optionen und gilt als (Datei)-Argument.
Manche Programme (wie z.B. java, cc oder xterm) halten sich leider nicht an diese
Konventionen und interpretieren -tx insgesamt als eine Option. . .
Neuere Programme erlauben z.T. auch mehrbuchstabige Optionen nach zwei Minuszeichen (z.B. --help), die dann natürlich nicht mit anderen kombiniert werden können.
Die Einleitung durch -- statt - vermeidet Konflikte mit den (klassischen) einbuchstabigen Optionen.
6
1.4
Typische Kommandos
Shell-interne Kommandos
Information
Kommunikation
Dateien
Kataloge
Kompaktieren
Kopieren
Betrachten
Anordnen
Untersuchen
Text ändern
Service
Prozesse
Rechnen
Programmieren
Subsysteme
cd echo pwd . . .
cal date df du id logname man tty
mail talk who write
chgrp chmod chown ln ls mv rm touch
find mkdir rmdir
gzip unzip zip
cp dd tar tee
cat file head less more od tail
pr sort uniq
cmp comm diff egrep fgrep grep wc
cut join paste split tr
at lpq lpr stty
kill nice nohup ps time
basename dirname expr
env false sleep test true
awk make sed sh vi
Die Klassifizierung ist nicht strikt. Manche Kommandos passen in mehrere Kategorien.
Es gibt natürlich noch viel mehr Kommandos. . .
7
1.5
1.5.1
Shell-Programmierung
Was ist ein Kommando?
Ein Kommando besteht aus einer Folge von Worten.
Das erste Wort in der Eingabe legt fest, welches Kommando ausgeführt wird:
$
$
$
$
test
date
/bin/date
./test
eingebaut oder Funktion
über PATH gesucht
absoluter Pfad
relativ, hier im aktuellen Katalog
Enthält das erste Wort keinen /, so wird unter den eingebauten Kommandos, dann den
Funktionen und dann in jedem Katalog gesucht, der in PATH angegeben ist. Die Variable wird normalerweise bei der Anmeldung ausreichend definiert.
$ echo $PATH
/home/elmar/bin:/home/elmar/bin/i686:/usr/local/bin:/usr/
local/gnu/bin:/usr/ucb:/usr/bin:/bin:/usr/X11R6/bin:/usr/
lib/java/bin
PATH kann den aktuellen Katalog als . oder als leeren Eintrag enthalten. Beim SuperUser enthält PATH den aktuellen Katalog a priori aus Sicherheitsgründen nicht.
type zeigt, wo ein Kommando im Dateisystem zuerst gefunden wird. Das Kommando
ist in der Shell eingebaut:
$ type date echo
date is /usr/bin/date
echo is a shell builtin
1.5.2
Was ist ein Wort?
Zwischenraum
besteht aus Leerzeichen und Tabulatorzeichen. Zwischenraum trennt Worte. Die
Folge newline wird insgesamt entfernt – sie ist kein Zwischenraum.
Worte
sind Zeichenfolgen, die durch Zwischenraum getrennt sind. Zitierter Zwischenraum (mit \ oder einfachen oder doppelten Anführungszeichen) zählt als Teil
eines Worts.
8
zitiert das nächste Zeichen; newline wird ignoriert.
’. . . ’
zitiert alle Zeichen außer einem einfachen Anführungszeichen.
". . . "
erlaubt Textersatz für Variablen, Kommandos und Arithmetik. \ zitiert ‘, ", $
und newline.
Kommentare
beginnen mit # am Wortanfang und reichen bis zum Zeilenende.
1.5.3
Textersatz für Variablen
Zuweisung an eine Shell-Variable ist ein Wort, das aus einem Variablennamen, einem
Gleichheitszeichen und dem neuen Wert besteht. Der neue Wert ist beliebiger Text, also
auch leer.
Die Werte von Shell-Variablen werden durch $name oder auch ${name} abgerufen.
Dabei werden die Werte an Zwischenraum (siehe IFS) in Worte zerlegt, wenn der Ausdruck nicht in doppelten Anführungszeichen ". . . " steht.
$ a="hallo welt"
$ echo $a
hallo welt
$ echo ${a}bc
hallo weltbc
$ echo $abc
$ ls $a
ls: hallo: No such file or directory
ls: welt: No such file or directory
$ ls "$a"
ls: hallo welt: No such file or directory
$ a=’$b’
$ echo $a
$b
Mit Doppelanführungszeichen kann man Variablen einigermaßen als Wertelisten verwenden, dabei können die Werte allerdings keinen Zwischenraum enthalten:
$ list=
$ for name in A B C; do
9
> list="$list $name.class"
> done
$ echo $list
A.class B.class C.class
Mit der export-Anweisung werden einzelne Shell-Variablen an die aus der Shell aufgerufenen Kommandos weitergereicht:
$ a=hallo
$ printenv a
$ export a
$ printenv a
hallo
Zuweisungen können auch unmittelbar vor einem Kommando stehen und gelten dann
nur für die Ausführung dieses Kommandos (export erfolgt dann automatisch):
$ x=x
$ x=y printenv x
y
$ echo $x
x
Die Shell setzt einige spezielle Variablen:
$1 . . . $9
$#
$* und $@
"$*"
"$@"
$?
Argumente des Interpreters (oder Funktion)
Anzahl der Argumente
alle Argumente
alle Argumente als ein Wort
alle Argumente als einzelne Wörter
Exit-Code des letzten Kommandos
Das System verwendet bestimmte Variablen – eine Auswahl:
HOME
IFS
LANG
LOGNAME
PATH
PS1
PS2
SHELL
TERM
Heimatkatalog (z.B. für cd)
trennende Zeichen für Worte (space, tab, newline)
Spracheinstellung (en_US)
Login des Benutzers
Suchpfad für Kommandos
Prompt (’$ ’)
Prompt bei Fortsetzung (’> ’)
Name der Shell
Terminaltyp (vt100)
10
1.5.4
Textersatz für Kommandos
Ein Kommando in $(. . . ) (oder ‘. . . ‘) wird durch seine Standard-Ausgabe ersetzt.
Zeilentrenner am Schluß werden dabei entfernt:
$ echo "user $(whoami) on ‘hostname‘"
user elmar on suleika
Kommandos werden auch innerhalb von ". . . " ersetzt, wobei dann nur ein Argument
als Resultat entsteht. Sonst wird die Ausgabe wie bei Variablen an den Zeichen in Worte
zerlegt, die in IFS stehen:
$ IFS=:
$ echo $(head -1 /etc/passwd)
root x 0 0 root /root /bin/bash
Allgemein schützen ’. . . ’ und ". . . " vor Nachzerlegung an IFS. Ungeschützte Argumente, Variablenwerte und Kommando-Ausgabe werden in Worte nachzerlegt, Muster
für Dateinamen aber nicht:
$ touch a b "a b"
$ ls -l
-rw-r--r-1 elmar
-rw-r--r-1 elmar
-rw-r--r-1 elmar
$ for i in [ab]*; do
> echo ":$i:"
> done
:a:
:a b:
:b:
1.5.5
inform
inform
inform
0 Mar 27 17:24 a
0 Mar 27 17:24 a b
0 Mar 27 17:24 b
Arithmetik mit Variablen
Ein ganzzahliger arithmetischer Ausdruck in $((. . . )) wird durch den numerischen
Wert des Ausdrucks ersetzt. Leider wird das nicht von allen Shells unterstützt. . .
$ x=1
$ x=$((x + 1))
$ echo $x
2
Es gibt praktisch alle aus C oder Java bekannten Operatoren.
11
1.5.6
Textersatz für Argumente
Argumente des Interpreters sind in $1 bis $9 gespeichert (entspricht dem args[] in
der main()-Methode in Java). Der Name des Shell-Skripts selbst ist $0.
Eine Funktion verwendet die gleichen Argumente wie die Shell selbst, das heißt, ein
Funktionsaufruf zerstört die Argumentliste der Shell:
$ echo $*
$ f() {
> echo foo
> }
$ f 3
foo
$ echo $*
3
Alle Argumente (auch mehr als 9) sind durch $* oder $@ erreichbar. "$*" liefert sie
als ein Wort, verkettet mit Leerzeichen. "$@" liefert sie als ein Argument pro Wort.
1.5.7
Dateinamen
Nach Ersatz von Variablen und Kommandos werden aus den nicht zitierten Wörtern –
also auch aus dem Ersatztext von Variablen – Dateinamen generiert. Aus einem Wort
entsteht jeweils eine alphabetisch sortierte Namensliste – die Listen werden nicht zusammengefügt. Das Resultat der Generierung wird weder nachersetzt noch an IFS
zerlegt.
$ cp *.java /tmp
$ ls */*.class
tmp/NeighborQueen.class
tmp/Queen.class
tmp/QueensIM.class
$ echo hi > ab
$ a=*
$ echo "$a"
*
$ echo $a
ab
tmp/QueensOO.class
tmp/SimpleQueen.class
tmp
Allgemein folgt, daß man Variablen und Kommandos beim Einsetzen wohl grundsätzlich mit ". . . " schützen sollte, falls man keine Zerlegung braucht:
12
$ read x
*
$ echo $x
ab tmp
1.5.8
Muster für Dateinamen
Es gibt eine Reihe von Sonderzeichen, die in Mustern für Dateinamen oder der caseAnweisung (siehe 1.5.11 auf Seite 15) eine besondere Bedeutung haben:
normalerweise stellt ein Zeichen sich selbst dar
\ ’ . . . ’ " . . . " Sonderbedeutung unterdrücken
beliebiges, einzelnes Zeichen
beliebig viele beliebige Zeichen
einzelnes Zeichen aus Klasse, auch Bereiche wie a-z
einzelnes Zeichen nicht aus Klasse
und dann ?
*
[. . . ]
[!. . . ]
|
oder (nicht für Dateinamen, nur bei case-Anweisung!)
Bei Dateinamen werden . am Anfang und / überall nur explizit erkannt. Die Muster
sind implizit links uns rechts verankert.
Beispiele:
*.java
[A-Z]*
[!A-Z]*
1.5.9
Java-Quellen
Dateinamen mit großem Anfangsbuchstaben
(fast) alle anderen Dateinamen (bis auf .*)
Ein-/Ausgabe-Umlenkung
Eine Ein-/Ausgabe-Umlenkung beginnt mit > (Ausgabe in Datei), >> (Ausgabe an
Datei anfügen), < (Eingabe aus Datei). Davor kann noch eine Ziffer stehen, die den
File-Deskriptor bezeichnet, auf den sich die Umlenkung bezieht: 0 (default) für die
Standard-Eingabe, 1 (default) für Standard-Ausgabe, 2 für Standard-Fehlerausgabe.
Der Rest des Worts oder das nächste Wort ist ein Dateiname.
$ wc *.java >output
$ javac X.java 2>errors
$ wc <errors
2
6
35
13
1.5.10
Zusammengesetzte Kommandos
einfaches Kommando
besteht aus einer expandierten Folge von Worten, abgeschlossen durch Zeilentrenner oder andere Zeichen (newline, ; oder &).
Kommando
ist ein einfaches Kommando oder eine Kontrollstruktur (siehe 1.5.11).
Pipeline |
ist eine Folge von Kommandos, unterteilt mit |. Die Standard-Ausgabe des Kommandos links in der Pipeline wird jeweils zur Standard-Eingabe des Kommandos
rechts in der Pipeline.
$ date | wc
1
6
30
$ date | tr a-z A-Z
WED APR 3 09:41:55 MEST 2002
$ du /tmp | sort -n | tail
4
/tmp/.font-unix
4
/tmp/elmar
4
/tmp/nscomm40-olaf/29939
4
/tmp/nscomm40-olaf/9539
4
/tmp/nscomm40-olaf/9772
8
/tmp/ksocket-elmar
8
/tmp/mcop-elmar
16
/tmp/nscomm40-olaf
444
/tmp/kde-elmar
588
/tmp
logische Liste && ||
ist eine Folge von Pipelines, unterteilt mit && oder ||. Die Folge wird von links
her abgearbeitet:
a && b
a || b
Kommando b nur, wenn Kommando a den Exit-Code 0 liefert.
Kommando b nur, wenn Kommando a nicht Exit-Code 0 liefert.
Liste newline ; &
ist eine Folge von logischen Listen, abgetrennt mit beliebig vielen Zeilentrennern
oder Semikolons, damit Kommandos nacheinander abgearbeitet werden. Eine mit
& beendete logische Liste wird asynchron abgearbeitet, das heißt, die Shell wartet
nicht auf das Prozeßende.
$ test -f file && rm file &
14
insgesamt im Hintergrund
1.5.11
Kontrollstrukturen
Ein Kommando ist entweder eine Kommando-Liste, also auch eine Pipeline oder ein
einfaches Kommando, oder es ist eine Kontrollstruktur:
for variable in wort . . .
do
liste
done
Beispiel:
$ for x in $(seq 0 9); do
> echo $x
> done
Das seq-Kommando kann Zahlensequenzen für for generieren.
while [ bedingung ]
do
liste
done
Eine Bedingung ist ein Boolescher Ausdruck, der (unter anderem) die folgenden Operatoren enthalten kann:
( ! )
-a -o [-n] -z = != -eq -ge -gt -le -lt -ne -d -f -r is true
is false
both and are true
either or is true
the length of is non-zero
the length of is zero
the strings are equal
the strings are not equal
is equal to is greater than or equal to is greater than is less than or equal to is less than is not equal to exists and is a directory
exists and is a regular file
exists and is readable
Vorsicht: Runde Klammern müssen durch Anführungszeichen geschützt werden!
15
Beispiel:
$ x=0
$ while [ $x != 10 ]; do
> echo $x
> x=$((x + 1))
> done
until [ bedingung ]
do
liste
done
Wie while-Schleife, aber negierte Bedingung.
if [ bedingung ]; then
liste
elif [ bedingung ]; then
liste
else
liste
fi
Der elif -Teil kann häufig wiederholt werden (und ist optional), der else-Teil ist ebenfalls
optional. Beispiel:
$ if [ ! -d $dir ]; then
> mkdir $dir
> fi
case wort in muster | . . . ) wie Dateimuster, erkennen auch /
liste
;; muster | . . . )
viele Fälle
liste
esac
Fallverteiler mit Musterbewertung. Nur der erste passende Fall wird ausgeführt:
$
>
>
>
>
>
>
case "$name" in [A-Z]*)
echo upper case
;; [a-z]*)
echo lower case
;; *)
echo something else
esac
16
{ liste ; }
Zusammenfassung von Kommandos
name() {
liste
}
definiert Funktion (Argumente sind $1 bis $9 bzw. $*, siehe 1.5.6)
Man kann rekursiv aufrufen, es gibt aber keine lokalen Variablen (ohne Sub-Shells zu
verwenden, die hier nicht erklärt werden).
Ein-/Ausgabe-Umlenkung ist für die ganze Kontrollstruktur möglich, denn sie gilt wieder als Kommando. Das führt dann aber zu Sub-Shells.
Der Exit-Code stammt vom letzten Kommando – if, while und until liefern Null,
wenn kein Kommando ausgeführt worden ist.
Vorsicht: Die ganzen steuernden Worte sind nicht reserviert; insbesondere sind nur die
runden Klammern reserviert, die geschweiften nicht!
1.5.12
Eingebaute Kommandos
Eine Reihe von Kommandos sind in der Shell eingebaut – Kommandos wie cd oder
exit wirken auf die Shell selbst, bei anderen wie echo oder test geschieht das aus
Effizienzgründen:
:
Kommentar; wird aber ausgeführt und liefert 0.
. datei
datei wird auf PATH gesucht und in der gleichen Shell ausgeführt – damit kann
man per Skript Variablen in der eigenen Shell setzen.
break [anzahl]
for-, while- und until-Schleifen verlassen.
cd [pfad]
Arbeitskatalog auf HOME oder pfad setzen.
continue [anzahl]
for-, while- und until-Schleifen fortsetzen.
echo [arg . . . ]
Argumente ausgeben (Vorsicht bei \).
eval arg . . .
Argumente einlesen, parsieren und ausführen – damit findet vor allem nochmals
17
Textersatz und Zerlegung statt:
$ a=hallo
$ b=’$a’
$ echo $b
$a
$ b=$b
$ echo $b
$a
$ eval b=$b
$ echo $b
hallo
exit [code]
Shell verlassen. Exit-Code ist code oder stammt vom letzten Kommando.
export [name . . . ]
Variablen für Export markieren oder exportierte zeigen.
pwd
Arbeitskatalog zeigen.
read name . . .
Eine Zeile einlesen, an IFS zerlegen und die Wörter an die Variablen zuweisen.
Restliche Wörter gehen (unzerlegt) an die letzte Variable.
return [code]
Funktion verlassen. Exit-Code ist code oder stammt vom letzten Kommando.
shift [anzahl]
Argumente „nach links schieben“. Das erste oder die anzahl ersten Argumente
gehen verloren, $*, $@ und $# werden korrigiert.
test [arg . . . ]
Bedingungen prüfen.
type name . . .
Ausgeben, was name als Kommando bedeutet.
unset name . . .
Variable oder Funktion löschen.
18
1.6
Make
Das make-Kommando ([Feldman]) erlaubt die automatisierte Ausführung von Kommandosequenzen in Abhängigkeit von Änderungen an Dateien.
Typische Anwendungen für make sind Fälle in denen Ausgabedateien über Kommandos (wie cc, javac oder latex) automatisiert aus Eingabedateien erzeugt werden.
Ein einfaches Beispiel:
Es gebe 3 Listen mit Namen, die sich gelegentlich (einzeln) ändern (z.B. weil sie von
unterschiedlichen Personen aktualisiert werden).
Aufgabe ist nun, mit minimalem Aufwand eine moeglichst permanent aktuelle Gesamtliste in originaler und zusätzlich noch in alphabetischer Reihenfolge zu unterhalten.
Lösung 1: Führe nach jeder Änderung in einer der drei Dateien „von Hand“ die
folgenden Befehle aus:
$ cat datei1 datei2 datei3 >liste
$ sort liste >liste.sortiert
Aber:
– Befehle „von Hand“ tippen ist lästig und fehleranfällig.
– Möglicherweise kann man Arbeit sparen, wenn man „weiß“, welche der
Dateien sich geändert haben.
– Vielleicht möchte man nicht immer alle Aktionen ausführen.
Lösung 2: Schreibe die Anweisungen zum Aktualisieren der Ausgabedateien einmal auf, den Rest kann ein Werkzeug erledigen.
Und genau dieses Werkzeug ist make:
liste:
datei1 datei2 datei3
cat datei1 datei2 datei3 >liste
liste.sortiert: liste
sort liste >liste.sortiert
Abbildung 1.1: Inhalt der Datei Makefile
$ make liste.sortiert
cat datei1 datei2 datei3 >liste
sort liste >liste.sortiert
19
Ein Makefile ist eine einfache Textdatei mit Anweisungen für das make-Kommando.
Der Name ist entweder makefile, Makefile oder kann über die -f Option von
make angegeben werden. Ein Makefile kann drei verschiedene Arten von „Anweisungen“ für make enthalten (alles zeilenorientiert, Eingabezeilen können bei Bedarf mit \
am Zeilenende fortgesetzt werden):
Variablendefinition
Auch make kennt – wie die Shell – Variablen. Allerdings sind diese getrennt
von den Shellvariablen: Eine in der Shell definierte Variable ist nicht automatisch
auch in make bekannt (und umgekehrt).
Variablen werden ähnlich wie in der Shell definiert:
variable = wort . . .
Die Regeln sind hier aber weniger strikt als in der Shell: Zwischenraum vor und
nach dem Gleichheitszeichen ist erlaubt (und wird ignoriert), und die Definition
geht immer bis zum Ende der aktuellen (logischen) Zeile, d.h. der Wert kann
Zwischenraum enthalten. Anführungszeichen habe keine besondere Bedeutung.
Die Werte von Shell-Variablen werden durch $(name) oder auch ${name} abgerufen. Dabei werden auch hier die Werte an Zwischenraum in Worte zerlegt, d.h.
man kann Listen bilden.
(Explizite) Regel
Ein Eintrag der Form:
ziel : quelle . . .
shell-kommandos
definiert ein „Ziel“, daß make erzeugen kann. Rechts von dem Doppelpunkt stehen alle Dateien, aus denen das Ziel erzeugt wird (Liste kann leer sein).
Alle folgenden Zeilen, die mit einem TAB eingerückt sind, enthalten die ShellKommandos zum Erstellen der Ziel-Datei.
Implizite Regel
Quasi eine „Wildcard“ für eine normale Regel.
Sieht genau wie eine explizite Regel aus, verwendet aber den Platzhalter % als
Symbol für eine beliebige Zeichenfolge im Namen des Ziels und der Quelle. Typisches Beispiel für Java:
%.class : %.java
javac -g $<
20
Es gibt in impliziten Regeln vordefinierte Variablen wie $@ (aktuelles Ziel), $<
(erste Datei aus Quell-Datei Liste), $ˆ (alle Quell-Dateien) etc.
Ein komplexeres Beispiel:
# java compiler, flags
CLASSPATH =
.
JAVAC =
javac -classpath $(CLASSPATH)
JAVADOC =
javadoc -classpath $(CLASSPATH)
JFLAGS =
-g
# list of classes to build and remove
SOURCES =
IO.java
CLASSES =
$(SOURCES:.java=.class)
CLEAN =
$(CLASSES) *.class
# wildcard rule
%.class : %.java
$(JAVAC) $(JFLAGS) $<
# default target
all :
$(CLASSES)
doc :
$(SOURCES)
rm -rf $@; mkdir $@
$(JAVADOC) -d $@ $(SOURCES)
# clean up
clean :
rm -f $(CLEAN)
rm -rf doc
21
Literaturverzeichnis
[ATS 94]
Axel T. Schreiner: Shell-Programmierung, Osnabrücker Schriften
zur Mathematik, 1994
[Kernighan 84]
Brian Kernighan, Rob Pike: The Unix Programming Environment,
Prentice-Hall, 1984
[Robbins]
Arnold Robbins: Opening the Software Toolbox, Linux Journal,
Volume 1, Number 2
[Feldman]
Stu Feldman: Make - A Program for Maintaining Computer Programs
22
Zugehörige Unterlagen
Herunterladen