Kornshell

aus Wikipedia, der freien Enzyklopädie
Wechseln zu: Navigation, Suche

Die Kornshell (Eigenbezeichnung KornShell, auch als ksh, ksh88 und ksh93 bezeichnet) ist ein von David Korn entwickelter Kommandozeileninterpreter wie auch die Beschreibung der Scriptsprache, welche durch diesen Interpreter implementiert wird. Ursprünglich für UNIX geschrieben finden sich heute Implementierungen nicht nur für UNIX-ähnliche Systeme, sondern auch für Microsoft Windows und AmigaOS.

Die Sprachbeschreibung selbst ist gemeinfrei, nicht jedoch jede Implementierung. Der originale Quellcode der ksh93 ist seit 2000 (bzw. 2005, siehe Geschichte) ebenfalls gemeinfrei.

Die KornShell (in der Version von 1988) bildete die Grundlage für die POSIX-Shell-Spezifikation und erfüllt den POSIX2-Standard.[1] Sie ist vollständig abwärtskompatibel mit der Bourne Shell (sh bzw. bsh) und übernimmt viele Neuerungen der C Shell (csh).

Geschichte[Bearbeiten]

Die KornShell - so die durch ihren Autor geprägte Schreibung[2] - wurde Anfang der 1980er Jahre von David Korn bei den Bell Labs der AT&T entwickelt und bei der USENIX-Konferenz am 14. Juli 1983 vorgestellt.[3] Sie war als Nachfolgerin der Bourne Shell konzipiert, unterschied sich von dieser aber durch wesentliche Verbesserungen: Job Control, eine, der C Shell nachempfundene Command History und Command Aliasing.

ksh88[Bearbeiten]

Die neue Shell wurde rasch zum Erfolg und wird heute noch von vielen Anbietern von Unix-Systemen ausgeliefert: HP-UX etwa hat eine eigene Version als Default-Shell, ebenso wird AIX (seit Version 4)[4][5] mit einer originalen ksh88 als Default-Shell ausgeliefert. Ende der 1980er-Jahre wurde die Spezifikation ksh88 festgelegt, welche die Grundlage für die Beschreibung des Command Interpreters im POSIX-Standard bildete und im Wesentlichen mit dieser identisch ist. Die Rechte an der ksh88 liegen bei AT&T sowie bei Novell.

ksh93[Bearbeiten]

1993 erfolgte eine grundlegende Überarbeitung der Shell wie auch ihrer Scriptsprache. Diese neue Spezifikation (bzw. Implementierungen, die ihr folgen) wird als ksh93 bezeichnet. Einzelne Versionen werden dabei durch angehängte Buchstaben gekennzeichnet, so ist etwa die aktuelle Version ksh93u, welche der Version ksh93t+ und deren Vorgängerin ksh93t folgte.

Bis zum Jahr 2000 war die Korn Shell proprietäre Software, die Rechte lagen bei AT&T und Lucent. 2000 wurden schließlich die Sourcen veröffentlicht, erst noch unter einer AT&T-eigenen Version einer gemeinfreien Lizenz, ab Version ksh93q (2005) unter der Common Public License.[6]

Die KornShell und ihr Umfeld[Bearbeiten]

Unterschiede zu und Gemeinsamkeiten mit anderen Shells[Bearbeiten]

Command Line Editing, File Name Completion[Bearbeiten]

Eine der wichtigsten Änderungen gegenüber ihrer Vorgängerin, der Bourne Shell, war die Möglichkeit, die eingegebene Kommandozeile zu wiederholen bzw. vor dem erneuten Ausführen zu ändern. Diese Funktion wurde von der C Shell Bill Joys übernommen, aber gegenüber dieser wesentlich ausgebaut: in der ksh standen von Beginn an drei Editier-Modi zur Verfügung, die alle das Verhalten gängiger Editoren nachahmten: vi, Emacs und XEmacs.

Ebenfalls neu war die Möglichkeit, Dateinamen automatisch komplettieren zu lassen, bzw., sich zu einem unvollständig eingegebenen Dateinamen während der Kommandoeingabe eine Liste aller passenden Dateien anzeigen zu lassen.

Mit der ksh93 wurde zusätzlich zur File Name Completion auch die Command Completion, also die Vervollständigung unvollständig angegebener ausführbarer Dateien, eingeführt. Diese Funktion ist mit jener der bash identisch.

Behandlung von Pipelines[Bearbeiten]

Im Gegensatz zur bash werden Pipelines in der ksh nicht automatisch in Subshells ausgeführt. Das hat gravierende Konsequenzen für den Gültigkeitsbereich von Variablen:

#!/usr/bin/ksh
typeset -i linenum=0
typeset    line=""
cat /path/to/input | while read line
do
  (( linenum += 1 ))
done
echo $linenum

In bash würde die letzte Zeile 0 ausgeben, weil die while..done-Schleife als Bestandteil einer Pipeline in einer Subshell ausgeführt wird und $linenum deshalb nur in der Subshell inkrementiert wird. In einer - echten - KornShell hingegen wird die Anzahl der Zeilen in der Datei ausgegeben. Viele Nachbauten (etwa pdksh) realisieren dieses Verhalten allerdings nicht, sondern verhalten sich in dieser Hinsicht wie bash.

FPATH-Variable[Bearbeiten]

Seit ihren ersten Versionen verfügt die ksh über die Systemvariable FPATH, die einen Standard-Suchpfad für Dateien mit Shell-Funktionen definiert, analog der Variablen PATH für ausführbare Dateien. Dies ermöglicht den Aufbau von Funktionsbibliotheken, die sich ähnlich wie Shared Libraries verhalten. Dies ist ein großer Vorteil gegenüber anderen Shells, insbesondere bash, die alle zu verwendenden Funktionen bei Scriptstart einparsen muss.

Floating-Point-Unterstützung[Bearbeiten]

Die ksh93 verfügt zusätzlich zur gewöhnlichen Integer-Arithmetik auch über den Datentyp Floating-Point und die zugehörigen Methoden zur Bearbeitung solcher Daten.

Coprocess-Facility[Bearbeiten]

Eine unter den verbreiteten Shells einzigartige Funktion ist die Fähigkeit, sowohl der ksh88 wie auch ksh93, Hintergrundprozesse asynchron abzuarbeiten und dennoch über Nachrichten zu steuern - das sogenannte Coprocess Facility. Dabei wird ein Prozess zwar im Hintergrund asynchron abgearbeitet, bleibt aber mit dem Vaterprozess über zwei Datenkanäle (ausgeführt als File-Deskriptoren 4 und 5) verbunden und kann über diesen bidirektionalen Kanal gesteuert werden.

Varianten[Bearbeiten]

Nicht zuletzt wegen der ursprünglich lizenzbelasteten Situation wurden im Laufe der Zeit wurden verschiedene Implementierungen der Korn Shell geschrieben, die mehr oder weniger kompatibel zur originalen Shell waren bzw. sind.

dtksh[Bearbeiten]

dtksh (Desktop ksh) ist eine Version der ksh93 zur Programmierung graphischer Oberflächen unter X11. Diese Version erweitert die ursprüngliche Scriptsprache um Anbindungen zum Common Desktop Environment bzw. Motif, X, Xt und tcl.

pdksh / mksh / oksh[Bearbeiten]

pdksh ist eine gemeinfreie Implementierung der Korn Shell, die allerdings in einigen Punkten wenig Kompatibilität aufweist (etwa werden Pipelines analog der bash und im Gegensatz zu allen ksh-Versionen in Subshells ausgeführt). Es werden die meisten Merkmale der ksh88 und einige wenige der ksh93 unterstützt. Zusätzlich bringt sie einige eigene Erweiterungen mit.

mksh ist ein pdksh-Derivat, bei dem auf einfachere Bedienbarkeit und schlanken, aber korrekten Code Wert gelegt wird. Dabei werden auch Verbesserungen von Projekten wie Debian und OpenBSD eingepflegt. Im Gegensatz zur OpenBSD-ksh ist mksh portabel und steht für verschiedene Plattformen zur Verfügung. Das Programm enthält auch viele Erweiterungen und Detailverbesserungen (zum Beispiel unbegrenzt große Arrays, oder ~/.mkshrc-Unterstützung), verzichtet jedoch bewusst auf den Code aufblähende Funktionalitäten wie eine bash-artige $PS1-Syntax; auch ist es nicht als Ersatz für /bin/sh gedacht. mksh wird vom MirOS-Projekt gewartet.

oksh ist eine Linux-Portierung der OpenBSD-Variante der Korn Shell, wobei im OpenBSD-Code nur so viel Änderungen wie nötig eingepflegt werden, um ihn unter Linux kompilierfähig zu machen. Diese Variante wird als Standard-Shell /bin/sh unter DeLi Linux eingesetzt.

Portierungen auf AmigaOS und Microsoft Windows[Bearbeiten]

SKsh ist eine Version für AmigaOS, die eine Anzahl Amiga-spezifischer Merkmale wie beispielsweise ARexx-Interoperabilität bietet.

Die MKS Korn Shell ist eine weitere kommerzielle Korn Shell-Implementierung. Sie ist Bestandteil von Microsofts Windows Services for UNIX (SFU) sowie dem Subsystem für UNIX-basierte Anwendungen (SUA) der Windows Vista Enterprise und Ultimate Editionen. Daß sie erhebliche Mängel in der Kompatibilität aufweist, wurde auf einer USENIX-Konferenz drastisch festgestellt. Die sich darum rankende Anekdote (hier wiedergegeben in den Worten David Korns) ging in die Geschichte ein:

“It was at a USENIX Windows NT conference and Microsoft was presenting their future directions for NT. One of their speakers said that they would release a UNIX integration package for NT that would contain the Korn Shell.

I knew that Microsoft had licensed a number of tools from MKS so I came to the microphone to tell the speaker that this was not the "real" Korn Shell and that MKS was not even compatible with ksh88. I had no intention of embarrassing him and thought that he would explain the compromises that Microsoft had to make in choosing MKS Korn Shell. Instead, he insisted that I was wrong and that Microsoft had indeed chosen a "real" Korn Shell. After a couple of exchanges, I shut up and let him dig himself in deeper. Finally someone in the audience stood up and told him what almost everyone in the audience knew, that I had written the 'real' Korn Shell. I think that this is symbolic about the way the company works.”

„Es geschah auf einer USENIX Windows NT-Konferenz und Microsoft präsentierte die weitere Entwicklung, die NT nehmen sollte. Einer ihrer Sprecher sagte, sie würden ein UNIX-Integrationspaket auf den Markt bringen und es würde eine Korn Shell enthalten.

Ich wußte, Microsoft hatte Lizenzen für einige Tools von MKS gekauft, deshalb kam ich zum Mikrophon und erklärte dem Sprecher, daß das keine "echte" Korn Shell und daß MKS nicht einmal kompatibel mit der ksh88 sei. Ich hatte nicht die Absicht, ihn bloßzustellen und erwartete, daß er nun die Kompromisse erklären würde, die Microsoft eingegangen war, indem sie die MKS Korn Shell wählten. Stattdessen bestand er darauf, daß ich daneben läge und daß Microsoft natürlich eine "echte" Korn Shell verwendete. Nach einigem Hin und Her schwieg ich und überließ es ihm, sich immer tiefer hineinzureiten. Schlußendlich stand jemand im Publikum auf und sagte ihm, was mittlerweile fast alle Zuhörer wußten: nämlich, daß ich die echte Korn Shell geschrieben hatte. Ich denke, das ist beispielhaft dafür, wie diese Firma arbeitet.“

– David Korn Tells All[7]

Einführung in die Scriptsprache KornShell[Bearbeiten]

Die KornShell war von Beginn an, insbesondere aber die ksh93, in erster Linie als Script-Interpreter und erst in zweiter Linie als interaktive Shell gedacht.[8] Die folgende Einführung geht auf die Unterschiede zwischen ksh88 und ksh93 nur am Rande ein, sondern versucht, die Eigentümlichkeiten der Programmiersprache KornShell überhaupt herauszuarbeiten.

Kommentare[Bearbeiten]

Die KornShell kennt nur eine Form von Kommentar: ab dem Doppelkreuz gilt alles bis zum Ende der Zeile als Kommentar, was dem // in C++ entspricht. Zeilenübergreifende Kommentare gibt es nicht.

Eine besondere Form von Kommentar ist der Shebang, der das ausführende Programm festlegt, aber dies ist eine Leistung des Kernels. Für die Shell ist dies ein Kommentar wie jeder andere auch. Soll der Octothorpe als Zeichen verwendet werden, so muß er in Anführungszeichen eingeschlossen oder escaped (durch ein vorangehendes Backslash-Zeichen '\' seiner besonderen Funktion entkleidet) werden.

#!/usr/bin/ksh
# Dies ist ein Kommentar
print - "Hello World."         # Kommentar: führe print-Statement aus
print - "#"                    # Octothorpe in Anführungszeichen wird als Zeichen verwendet
print - \#                     # escapeter Octothorpe
exit 0

Positionale und benannte Variablen, Here-Documents[Bearbeiten]

Variablen werden in der KornShell wie schon in der Bourne Shell durch ein Dollarzeichen ('$') und einen in geschweifte Klammern eingeschlossenen Bezeichner angesprochen (die geschweiften Klammern können in manchen Fällen auch weggelassen werden). Bei der Zuweisung allerdings wird lediglich der Bezeichner verwendet.

#!/usr/bin/ksh
typeset variable="Hello World."           # Zuweisung
print - ${variable}                       # Verwendung der Variablen
print - $variable                         # Verwendung, alternative Form
exit 0

Benannte Variablen entsprechen dem, was in anderen Hochsprachen als Variablen bezeichnet wird: ein Bezeichner, der einen Speicherplatz referenziert, in welchem ein Wert abgelegt sein kann. Die KornShell erfordert dabei - zum Unterschied von anderen Hochsprachen - keine formale Deklaration und verlangt auch keine explizite Typisierung. Gleichwohl kann - und soll(!), schon im Sinne der Lesbarkeit und Dokumentation - mittels des Keywords typeset eine Deklaration samt Datentyp erfolgen, insbesondere dann, wenn dieser von String abweicht. Als Datentypen stehen zur Verfügung:

  • String
  • Integer
  • Float (nur ksh93)
  • Compound (nur ksh93)
  • Array

Darüber hinaus kann jede Variable, unabhängig vom Typ, als String verwendet werden. Diese Variablen zeichnen sich dadurch aus, daß sie Namen tragen, weshalb sie benannte Variablen genannt werden.

Daneben gibt es unbenannte, sogenannte positionale Variablen, die automatisch im Falle von Scripten mit den übergebenen Kommandozeilen-Parametern, im Falle von Shell-Funktionen mit den übergebenen Argumenten gefüllt werden. Sie werden mit Zahlen bezeichnet (${0}, ${1}, ${2}, usw.), wobei ${0} immer den Namen des Programms bzw. der Funktion enthält.

Mit Ausnahme von $0 können positionale Variablen mit dem Keyword shift abgearbeitet werden. shift löscht den Inhalt der Variablen $1 und belegt dann $1 mit dem Wert von $2, $2 mit dem Wert von $3 .. $n-1 mit dem Wert von $n:

#!/usr/bin/ksh
print - "Name des Scripts............: ${0}" 
print - "Erstes übergebenes Argument : ${1}" 
print - "Zweites übergebenes Argument: $2"      # alternativ auch ohne Klammern
print - "Drittes übergebenes Argument: $3" 
 
shift
print - "Erstes übergebenes Argument : $1 (war vorher $2)" 
print - "Zweites übergebenes Argument: $2 (war vorher $3)"
print - "Drittes übergebenes Argument: $3 (war vorher $4)" 
 
exit 0

In Verbindung mit einer Schleife kann so eine bei Programmerstellung unbekannte Anzahl von übergebenen Parametern stückweise abgearbeitet werden.

Eine lediglich in manchen Shell-Sprachen anzutreffende Besonderheit ist das Here-Document. Es ist ein mit einem feststehenden Text gefüllter String, der aber nicht wie eine Variable deklariert, sondern lediglich einmalig, z.B. als Input eines Kommandos, verwendet wird. Allerdings können innerhalb eines Here-Documents Variablen verwendet werden, die bei Ausführung des Scripts durch ihre Inhalte ersetzt werden.

#!/usr/bin/ksh
typeset chMsg="Hello World."
mail recipient@remote.system.com <<EOF
Hallo recipient,
der Text der Nachricht lautet: $chMsg
EOF 
exit 0

Alles zwischen den Begrenzern EOF (die Begrenzer sind frei wählbare Bezeichner) wird als Eingabe an das Kommando mail geschickt, $chMsg wird durch den oben zugewiesenen Wert der Variablen ersetzt. In anderen Hochsprachen entsprechen den Here-Documents am ehesten String-Literale, in C++ etwa Raw String Literals.

Schleifen, Verzweigungen[Bearbeiten]

Schleifen und Verzweigungen sind kompatibel mit denen der Bourne Shell, von der sie bezogen sind. Die KornShell stellt drei Arten von Schleifen zur Verfügung: for, while und until.

Die for-Schleife entspricht im Verhalten dem von anderen Programmiersprachen Gewohnten: eine Liste von Werten wird iterierend einer Schleifenvariablen zugewiesen und jeweils ein Durchlauf des Schleifen-Körpers mit diesem Wert ausgeführt.

for Variable in Liste von Werten
do
  Liste von Kommandos
done

Zum Unterschied von den meisten Sprachen werden allerdings keine Zahlen- (Integer-) Werte iteriert, sondern Strings, die aus einer feststehenden Liste entnommen werden. Diese feststehende Liste kann allerdings auch Wildcards enthalten:

#!/usr/bin/ksh
typeset chLoopVar=""
 
# ---------------------------- Schleife mit Festwerten
for chLoopVar in a b c d e ; do
  print - "Der Wert der Variablen chLoopVar ist: $chLoopVar"
done
 
# ---------------------------- Schleife mit Files
print - "Eine Liste von txt-Dateien:"
for chLoopVar in *txt ; do
  print - "     -> $chLoopVar"
done
 
exit 0

Die while- und die until-Schleife sind sowohl syntaktisch gleich wie auch logisch äquivalent, mit dem Unterschied, daß die until-Schleife ausgeführt wird, bis eine bestimmte Bedingung eintritt, die while-Schleife hingegen, solange eine bestimmte Bedingung erfüllt ist. Die folgenden Ausführungen zur while-Schleife gelten deshalb sinngemäß auch für die until-Schleife.

Die while-Schleife arbeitet etwas anders als von anderen Sprachen gewohnt, weil die KornShell ursprünglich keine eigene Methode für Vergleiche kannte und sich deshalb des externen Kommandos test bediente. Mittlerweile hat die KornShell zwar eine eingebaute Funktion, die diesem Kommando entspricht, dennoch hat sich die Syntax der Schleife nicht geändert. while führt den Schleifenkörper so lange aus, wie ein angegebenes Kommando den Error Level 0 (entspricht TRUE) zurückgibt.

while Kommando ; do               
  Liste von Kommandos               
done
 
until Kommando ; do
  Liste von Kommandos
done

Wie das folgende Beispiel zeigt, ersetzen in der KornShell while-Schleifen die in anderen Sprachen eingesetzten for-Schleifen. Das zweite Beispiel zeigt die Flexibilität, die durch Einsatz des externen Kommandos gewonnen wird. Das shellinterne Kommando read wird in Verbindung mit einer Pipeline benutzt, einen Datenstrom zeilenweise zu verarbeiten:

#!/usr/bin/ksh
typeset -i iLoopVar=0
typeset    chLine=""
 
# ------------------------------- while-Schleife als for-Schleifen-Ersatz
while [ $iLoopVar -le 10 ] ; do
  print - "Wert von iLoopVar: $iLoopVar"
  (( iLoopVar += 1 ))                     # inkrementiere iLoopVar
done
 
# -------------------------------  listet alle Kommandos mit 3 Buchstaben in /usr/bin
find /usr/bin -name "???" -print | while read chLine ; do
  print - "Kommando: $chLine"
done
 
exit 0

Die KornShell kennt zwei Arten der Verzweigung: if..fi und case..esac.

if verwendet wie auch while ein externes Programm, um den benötigten logischen Wert zu generieren. if kann optional mittels des Keywords elif auch mehrere Bedingungen verarbeiten, ebenfalls optional ist ein bei Nichtzutreffen aller vorheriger Bedingungen auszuführender else-Zweig.

if Kommando ; then
  Liste von Kommandos
elif Kommando ; then
  Liste von Kommandos
elif Kommando ; then
  Liste von Kommandos
...
else
  Liste von Kommandos
fi

Bei üblichen Vergleichen wird dafür test bzw. dessen eingebautes Pendant benutzt, es kann aber auch ein beliebiges Programm ausgeführt und - abhängig von dessen Rückgabewert - eine Aktion gestartet werden:

#!/usr/bin/ksh
typeset -i iIn=0
 
# ------------------------------- einfaches if
if [ 1 -eq 1 ] ; then
  print - "1 ist tatsächlich gleich 1"
fi
 
# ------------------------------- if-else
if /path/to/program -opt arg1 arg2 ; then
  print - "Programm program wurde ohne Fehler beendet."
else
  print - "Programm program lieferte einen Fehler zurück."
fi
 
# ------------------------------- mehrstufiges if
print - "Geben Sie eine Ziffer (0-3) ein:" ; read iIn
if [ $iIn -eq 0 ] ; then
  print - "Sie haben 0 eingegeben."
elif [ $iIn -eq 1 ] ; then
  print - "Sie haben 1 eingegeben."
elif [ $iIn -eq 2 ] ; then
  print - "Sie haben 2 eingegeben."
elif [ $iIn -eq 3 ] ; then
  print - "Sie haben 3 eingegeben."
else
  print - "Sie haben was anderes eingegeben."
fi
 
exit 0

case wertet einen einzelnen Ausdruck durch Variablenexpansion aus und führt aus mehreren alternativen Codeblöcken abhängig von dessen Wert (das kann eine Shell Regular Expression, auch bekannt als File Glob, sein) einen davon durch. Das entspricht annähernd dem aus Pascal bekannten case .. of bzw. dem switch() aus C.

case Ausdruck in
  Wert)
    Kommando
    ...
  ;;
 
  Wert)
    Kommando
    ...
  ;;
  ...
esac

Das obige Beispiel, mit case anstatt if ausgeführt, würde lauten:

#!/usr/bin/ksh
typeset -i iIn=0
 
print - "Geben Sie eine Ziffer (0-3) ein:" ; read iIn
case $iIn in
  0)
    print - "Sie haben 0 eingegeben."
    ;;
 
  [123])                                            # 1, 2 oder 3 als Regexp
    print - "Sie haben 1, 2 oder 3 eingegeben."
  ;;
 
  *)                                                # default-Ast
    print - "Sie haben etwas anderes eingegeben."
  ;;
esac
 
exit 0

Funktionen[Bearbeiten]

Wie in allen anderen prozeduralen Programmiersprachen gibt es auch in der KornShell die Möglichkeit, logisch in sich geschlossene und/oder oftmals wiederkehrende Codeteile in Subroutinen - hier Funktionen genannt - auszulagern. Die Syntax ist mit jener der Bourne Shell bzw. der POSIX-Shell identisch, die KornShell versteht beide Varianten:

function Funktionsname     # Bourne Shell-artig
{
     Kommando
     Kommando
     ...
}

Funktionsname ()           # POSIX-Shell-artig
{
     Kommando
     Kommando
     ...
}

Zum Unterschied von anderen Programmiersprachen wird die Ein- bzw. Ausgabe allerdings regelmäßig dazu verwendet, Eingaben von anderen Programmteilen zu empfangen bzw. Ergebnisse an andere Programmteile zu übermitteln (Pipelining). In dieser Hinsicht verhalten sich Funktionen in der Shell ähnlich wie externe Programme.

Funktionsargumente werden - analog zu Kommandozeilenparametern - mittels positionaler Variablen übergeben. Mit dem Keyword return (optional von eine Int-Wert 0-255 gefolgt) kann der Rücksprung ins aufrufende Programm erfolgen und ein Funktionsergebnis, das von diesem als Error Level abgefragt und behandelt werden kann. Jede Funktion sollte deshalb mindestens ein solches return-Kommando (am Ende) enthalten.

#!/usr/bin/ksh
 
function pShowText
{
  print - "Dies ist ein Beispieltext."
  print - "Bei Ausführung der Funktion pShowText()"
  print - "wird er auf <stdout> ausgegeben."
  return 0
}
 
function pShowAnyText
{
  typeset iCnt=0
  while [ "$1" != "" ] ; do
    print - "$1"
    (( iCnt += 1 ))
    shift
  done
  return $iCnt
}
 
# --------- Hauptprogramm
typeset iRetVal=0
 
print - "Hier wird pShowText() aufgerufen:"
pShowText
print - "das Ergebnis kann auch in einer Pipeline verarbeitet werden:"
pShowText | grep 'ei'        # zeigt alle Zeilen, in denen "ei" vorkommt, also die ersten beiden
 
print - "pShowAnyText() gibt alle übergebenen Argumente zeilenweise aus:"
pShowAnyText "erste Zeile" "zweite Zeile" "dritte Zeile"
iRetVal=$?                   # sichert den Rückgabewert von pShowAnyText()
print - "Es wurden $iRetVal Argumente an pShowAnyText() übergeben."
 
exit 0

Variablenexpansion oder Parameter Substitution[Bearbeiten]

Ein wesentlicher Unterschied zwischen Shell-Sprachen und herkömmlichen Programmiersprachen ist die Behandlung von Variablen: in einer gewöhnlichen Hochsprache ist eine Variable letztlich ein Speicherplatz, in dem ein Wert abgelegt sein und der mit einem Namen angesprochen werden kann. In der ksh (wie auch der bash und ähnlichen Sprachen) ist eine Variable zwar ebenfalls ein Platz zum Ablegen von Werten, aber als direkte Operation existiert nur die Zuweisung. Alle anderen Arten, die Variable anzusprechen, sind mehr oder minder komplexe Funktionen, die den Inhalt der Variablen als Argument bekommen, ihn bearbeiten und das Ergebnis dieser Bearbeitung ausgeben. Der Variableninhalt bleibt dabei selbst aber unverändert.

Die einfachste dieser Funktionen ist $<Bezeichner>, bzw. ${<Bezeichner>}, welche den Inhalt der Variablen unverändert wiedergibt. Hingegen gibt etwa ${#<Bezeichner>} die Länge der (String-)Variablen <Bezeichner> an und entspricht damit der C-Funktion strlen().

Der Interpreter wertet dabei in Kommandozeilen im Zuge des Command Line Parsing zuerst diese Variablenausdrücke aus und ersetzen sie durch ihr Ergebnis, bevor die so entstandene tatsächliche Kommandozeile auswertet wird. Die folgende Übersicht zeigt einige Möglichkeiten, den Variableninhalt umzuformen:

${<Bezeichner>}, $<Bezeichner>
Inhalt der Variablen <Bezeichner> ohne Änderung
${#<Bezeichner>}
Länge der Variablen <Bezeichner>
${<Bezeichner>:-<Wert>}
Wenn die Variable <Bezeichner> deklariert und ihr Inhalt ungleich Null (bzw. dem leeren String) ist, dann wird dieser Inhalt ausgegeben, ansonsten der im zweiten Teil des Ausdrucks angegebene.
${<Bezeichner>:=<Wert>}
Wie ${<Bezeichner>:-<Wert>}, aber stattdessen wird der Variablen <Bezeichner> der sich ergebende Wert zugewiesen. Es entspricht
<Bezeichner>="${<Bezeichner>:-<Wert>}"
Dies wird üblicherweise verwendet, um Variablen mit Defaultwerten zu versorgen. Bei diesem wie auch allen ähnlichen Expansionen werden die dem Bezeichner folgenden Ausdrücke nur im Bedarfsfalle ausgewertet. Ungültige Ausdrücke können so für längere Zeit unentdeckt bleiben, was eines der (durch entsprechende Tests zu vermeidenden) Risiken bei größeren Shell-Scriptingprojekten darstellt.
${<Bezeichner>#<regexp>}, ${<Bezeichner>##<regexp>}
Wenn die angegebene <regexp> den Beginn des Inhalts der Variablen Bezeichner matched, dann wird dieser Inhalt, vermindert um jenen Teil, der matched, ausgegeben, ansonsten der gesamte Inhalt. Auf diese Weise können Teile des Inhalts einer Variablen abgeschnitten werden. Bei der Variante mit # wird der kleinste matchende Teil abgeschnitten, bei ## der längste. Beispielsweise schneidet der Ausdruck ${<PathName>##*/} vom Pfadnamen alles bis zum letzten / ab, was etwa dem Kommando basename entspricht.
${<Bezeichner>%<regexp>}, ${<Bezeichner>%%<regexp>}
Ähnlich wie ${<Bezeichner>#<regexp>} bzw. ${<Bezeichner>##<regexp>}, nur daß der abzuschneidende Teil nicht vom Beginn, sondern vom Ende des Variableninhalts gematched wird. Das Kommando dirname kann etwa durch die Expansion ${<Bezeichner>%/*} emuliert werden.
#!/usr/bin/ksh
typeset chVar="hello world"
 
print - "Inhalt der Variablen chVar: $chVar"
print - "Länge der Variablen chVar.: ${#chVar}"
print - "Defaultwert...............: ${chVar:-foo} hingegen: ${notdeclared:-foo}"
 
chVar="/path/to/some/file"
print - "Pattern entfernen..........: ${chVar##*/} bzw.: ${chVar%/*}"
 
exit 0

Literatur[Bearbeiten]

  •  Bolsky, Morris I.; Korn, David A.: The KornShell command and programming language. Prentice Hall, Englewood Cliffs, N.J. 1989, ISBN 0-13-516972-0.
  •  Bolsky, Morris I.; Korn, David A.: The new KornShell command and programming language. Prentice Hall PTR, Upper Saddle River, N.J. 1995, ISBN 0-13-182700-6.
  •  Rosenberg, Barry: KornShell Programming Tutorial. Addison-Wesley Professional, Boston, M.A. 1991, ISBN 978-0201563245.
  •  Rosenberg, Barry: Hands-On KornShell93 Programming. Addison-Wesley Professional, Boston, M.A. 1998, ISBN 978-0201310184.

Weblinks[Bearbeiten]

Einzelnachweise[Bearbeiten]

  1. The Open Group Base Specifications; 2. Shell Command Language. Abgerufen am 23. Mai 2013 (englisch).
  2. Homepage des KornShell-Projekts. Abgerufen am 19. Juni 2013 (englisch).
  3. David Korn, KSH - A Shell Programming Language, pp 191-202, USENIX Conference Proceedings, Summer 1983, Toronto, Ont.
  4. AIX v6.1 Infocenter. Abgerufen am 24. Mai 2013 (englisch).
  5.  Andreas Siegert: AIX Survival Guide. 1 Auflage. Addison-Wesley Professional, Boston 1996, ISBN 978-0201593884, S. 488.
  6. Package Notes and Changes (Changelog der ksh93). Abgerufen am 23. Mai 2013 (englisch).
  7. David Korn Tells All (Question 5, "True Story?"). Abgerufen am 24. Mai 2013 (englisch).
  8. David Korn Tells All (Question 1, "Comparison"). Abgerufen am 8. Juni 2013 (englisch).