![]() |
Vorlesung "UNIX"von Prof. Jürgen Plate |
Die Shell ist der Kommandointerpreter von UNIX. Es haben sich drei Typen entwickelt:
UNIX-Benutzer sind "mündig"! Was heißt das? Wenn Sie ein Kommando eingeben, das die gesamte Platte löscht, fragt das Programm nicht noch einmal nach, ob Sie das auch wirklich wollen, sondern löscht die Platte sofort.
Beim Testen von Shell-Programmen hilft das Kommando
echo [Argumente]
Dieses Kommando gibt die Argumente auf dem Bildschirm aus. Für den Einsteiger ist das Kommando wichtig, weil er so die Kommandobearbeitung der Shell recht gut verfolgen und studieren kann (Einstreuen von echo-Kommandos in die Befehlsfolge).
Shell Setup-Dateien (z . B. ".profile") führen typischerweise mindestens folgende Tätigkeiten aus:
Je nachdem, welche Shell eingesetzt wird, gibt es unterschiedliche Setup-Dateien.
Die TC-Shell verhält sich bis auf eine Ausnahme wie die C-Shell. Lediglich, wenn die Datei ".tcshrc" im Home-Verzeichnis des Benutzers steht, wird sie anstelle von ".cshrc" ausgeführt.
Die Eingabeumleitung erfolgt durch das Zeichen "<", gefolgt von einem Dateinamen.
Kommando < Dateiname
Statt z. B. beim write-Kommando den Text direkt einzugeben, kann auch einen Datei an ein anderes Terminal gesendet werden:
write markus < Nachricht
Falls die Datei noch nicht vorhaden war, wird sie automatisch angelegt. Falls die Datei schon vorhanden ist, wird sie überschrieben, d. h. es wird immer ab dem Dateianfang geschrieben.
Kommando > Dateiname
Fehlermeldungen (stderr) erscheinen nach wie vor auf dem Bildschirm. Beispiel: Ausgabe der Verzeichnisbelegung in einen Datei:
ls -l > info
Kommando 2> Fehlerdatei
(Die Umleitung der Standardausgabe ist nur die Kurzform von Kommando 1> Dateiname). Natürlich ist eine beliebige Kombination von Ein- und Ausgabeumleitung möglich, z. B.
Kommando < Eingabedatei > Ausgabedatei 2> Fehlerdatei
Kommando >> Sammeldatei
Dazu ein paar Beispiele:
Dateiliste und aktive Benutzer in einen Datei schreiben:
ls -l > liste
who >> liste
Durch Umleitung von Ein- und Ausgabe läßt sich auch unterdrücken. Für die Ausgabe schreibt man
Kommando > /dev/null
oder für die Fehlerausgabe
Kommando 2> /dev/null.
Beides läßt sich auch kombinieren:
Kommando > Ergebnisdatei 2> /dev/null.
Will man ein Programm mit einem beliebigen Eingabedatenstrom versorgen, schreibt man
Kommando < /dev/zero.
Die Umleitung von stout und stderr in dieselbe Datei würde prinzipiell eine zweimalige Angabe der Datei (eventuell mit einem langen Pfad) erfordern. Für die Standarddateien werden in solchen Fällen spezielle Platzhalter verwendet:
&0 | Standardeingabe |
&1 | Standardausgabe |
&2 | Standard-Fehlerausgabe |
Kommando > ausgabe 2>&1
Wenig bekannt ist der Bourne-Shell-Operator <>. Er öffnet eine Datei zum Lesen und Schreiben und verbindet sie mit der Standardeingabe. Fehlende Dateien legt er automatisch an, im Gegensatz zu > löscht er jedoch nicht den Inhalt bestehender Dateien. Gut eignet sich <> vor allem für den Zugriff auf Geräte, die eine bidirektionale Verbindung voraussetzen - etwa Terminals oder Modems.
Die Bourne-Shell kann noch mehr: Man kann einen beliebigen Kommunikationskanal umlenken, indem er dessen Kennzahl direkt vor das Größer oder Kleiner-Zeichen schreibt. Wie schon erwähnt, steht '0' für die Standardeingabe, 'l' und '2' stehen für die Standard- beziehungsweise Fehlerausgabe.
Allgemein gilt also:
Mit den Bourne-Shell-Operatoren <& und >& lassen sich Ein- und
Ausgabekanäle miteinander verbinden. Vor dem Operator darf die Nummer des
umgeleiteten Kanals stehen, dahinter muß die des Quell- beziehungsweise
Zielkanals folgen. Die häufigste Konstruktion >datei 2>&1 leitet
Standard- und Fehlerausgabe in dieselbe Datei um.
cat <a <b >c >dkopiert den Inhalt der Datei b in die Datei d. Als Seiteneffekt legt es eine leere Datei c an oder löscht den Inhalt von c, falls die Datei schon existierte.
Mitunter genügen die drei Standard-Kommunikationskanäle nicht, um eine Aufgabe zu erfüllen. Soll ein Skript etwa den Inhalt dreier Dateien miteinander vermengen, benötigt es zusätzliche Eingabekanäle. In der Bourne-Shell lassen sich weitere Kanäle mit den normalen Umleitungsoperatoren öffnen; der Benutzer muß lediglich die Nummer des gewünschten Kanals angeben. Mit den Umleitungsoperatoren <& und >& kann er die neuen Kanäle für einzelne Befehle öffnen, zum Beispiel:
# Dateimischer while read X <&3 && read Y <&4 && read Z <&5 do echo $X $Y $Z done 3<Datei-1 4<Datei-2 5<Datei-3Die Anzahl der offenen Kanäle ist durch die Shell oder das Betriebssystem begrenzt. Portable Skripte dürfen nur die Kanäle 0 bis 9 verwenden. Boume-Shell-Benutzer verwenden eine Spezialform des Befehls exec: Stehen hinter dem Befehlswort nur Umleitungen, aber keine Argumente, leitet die Shell die gewünschten Kanäle permanent um. Ist man zum Beispiel an Fehlermeldungen nicht interessiert, kann man sie vernichten mit
exec 2>/dev/nullSoll eine Umleitung später aufgehoben werden, kann man den ursprünglichen Kanal duplizieren:
exec 3<&0 <dateiverbindet beispielsweise die Standardeingabe mit einer Datei,
exec <&3stellt die alte Verbindung wieder her. Der Ordnung halber schließt man mit exec 3<& den zusätzlichen Eingabekanal, wenn man ihn nicht mehr braucht. Analog dazu schließt der Operator x>&- einen Ausgabekanal.
Kommando 1 | Kommando 2
Beispiel: Ausgabe der Dateien eines Verzeichnisses mit der Möglichkeit, zu blättern:
Natürlich können auch mehrere Kommandos hintereinander durch Pipes verbunden werden:
Kommando 1 | Kommando 2 | Kommando 3 | Kommando 4 | ...
Pipelines haben Vorrang vor anderen Formen der Ein- und Ausgabeumleitung. Bevor die Shell mit der Ausführung der Einzelbefehle und der dazugehörenden Umleitungen beginnt, baut sie die gesamte Pipeline zusammen: Sie erzeugt für jeden Abschnitt einen neuen Prozeß und verbindet die Standardausgabe jedes Prozesses mit der Standardeingabe des Nächsten. Will der Anwender die Fehlerausgabe eines Programms ebenfalls durch die Pipeline schicken, kann er in Bourne-Shell-Skripten
foo 2>&1 | barschreiben. Da die Shell die Pipeline-Verbindung zuerst herstellt, landen die Fehlermeldungen vom Programm foo auf der Standardeingabe von bar.
Kommandofolgen, die durch Pipes verbunden sind, werden auch als "Filter" bezeichnet. Einige nützliche Filter sind in jedem UNIX-System verfügbar. Zum Beispiel:
head [-n] [datei(en)]
Ausgabe der ersten n Zeilen aus den angegebenen Dateien. Voreinstellung ist 10
Zeilen. Wird keine Datei angegeben, liest head von der Standardeingabe.
tail [-/+n] [bc[f|r]] [datei]
Ausgabe der letzten n Zeilen einer Datei. Voreinstellung für n ist 10. Wird
keine Datei angegeben, liest tail von der Standardeingabe.
Optionen | |
+n | ab der n. Zeile ausgeben |
-n | die letzten n Zeilen ausgeben Wird hinter die Zahl n ein 'b' gesetzt (z. B. -15b), werden nicht n Zeilen, sondern n Blöcke ausgegeben. Wird hinter die Zahl n ein 'c' gesetzt (z. B. -200c), werden nicht n Zeilen, sondern n Zeichen (characters) ausgegeben. |
-r | Zeilen in umgekehrter Reihenfolge ausgeben (letzte zuerst). Geht nicht bei GNU-tail - stattdessen kann man das Programm toc verwenden. |
-f | tail am Dateiende nicht beenden, sondern auf weitere Zeilen warten. (Ende des Kommandos mit der CTRL-C-Taste). Damit kann man z. B. Logfiles beobachten, die ständig wachsen. |
Mittels head und tail lassen sich beispielsweise auch ganz bestimmte Zeilen aus einer Datei extraihieren - wobei dieses Kommandos nicht die einzige Möglichkeit darstellen. Hier einige Beispiele für Kommandoverkettungen (die mit '#' beginnenden Zeilen sind Kommentarzeilen):
# 5. Zeile der Datei foo.txt head -5 foo.txt | tail -1 # die drittletzte und vorletzte Zeile von foo.txt tail -3 | head -2
tee [-i] [-a] [datei]
Pipe mit T-Stück: Kopiert von stdin nach stdout und schreibt die Daten gleichzeitig
in die angegebene Datei.
Optionen | |
-i | Ignorieren von Interrupts (Unterbrechungs-Taste) |
-a | Anhängen der Info an die angegebene Datei (Voreinstellung: Überschreiben der Datei) |
wc [-lwc] [Datei(en)]
Dieses Kommando zählt Zeilen, Worte oder Zeichen in einer Datei. Wird kein
Dateiname angegeben, liest wc von der Standardeingabe. Normalerweise zählt
man damit in Skripten irgendwelche Ergebnisse. Optionen:
-l | Zähle Zeilen |
-w | Zähle Worte |
-c | Zähle Zeichen |
Weitere Filter sind more, less, tr, nl, .... Diese Kommandos werden in späteren Abschnitten behandelt.
# erstmal Named Pipe erzeugen mknod roehre p # nun die Daten verarbeiten tail -f roehreStatt einer Ausgabe auf dem Bildschirm können die Daten auch anderweit verarbeitet werden.
* | Der Stern steht für eine beliebige Zeichenfolge - oder für
überhaupt kein Zeichen. Dazu ein Beispiel: "ab*" steht für alle Dateinamen, die mit "ab" anfangen, auch für "ab" selbst ("ab", "abc", "abcd", "abxyz", usw.). |
? | Das Fragezeichen steht für genau ein beliebiges
Zeichen. Zum Beispiel: "?bc" steht für alle Dateinamen mit 3 Zeichen, die auf "bc" enden ("abc", "bbc", "1bc", "vbc", "xbc", usw.), nicht jedoch für "bc". |
[ ] | Die eckige Klammer wird ersetzt durch eines der in der Klammer stehenden Zeichen. Auch ein Bereich ist möglich, z. B. [a-k] = [abcdefghijk]. Beispiel: "a[bcd]" wird ersetzt durch "ab", "ac" und "ad". Soll das Minuszeichen selbst in die Zeichenmenge aufgenommen werden, muß es an erster Stelle stehen (gleich nach der öffnenden Klammer). |
[! ] | Die eckige Klammer mit Ausrufezeichen wird ersetzt durch eines der nicht in der Klammer stehenden Zeichen, zum Beispiel: "[!abc]" wird ersetzt durch ein beliebiges Zeichen außer a, b oder c. Soll das Ausrufezeichen selbst in die Zeichenmenge aufgenommen werden, muß es an letzter Stelle stehen. |
\ | Der Backslash hebt den Ersetzungsmechanismus für das folgende Zeichen auf. Beispiel: "ab\?cd" wird zu "ab?cd" - das Fragezeichen wird übernommen. Wichtig: Bei der Umleitung von Ein- und Ausgabe werden Metazeichen in den Dateinamen hinter dem Umleitungszeichen nicht ersetzt. |
Beispiele für die Anwendung:
ls -l a*
listet alle Dateien, die mit "a" anfangen
ls test? listet alle Dateien die mit "test" anfangen und 5 Zeichen lang sind ("test1", "test2", "testa")
ls /dev/tty1[1-9] listet alle Terminalbezeichnungen mit einer 1 in der Zehnerstelle ("tty11", "tty12", ... , "tty19")
Lebenswichtig:
Der * ist ein gefährliches Zeichen, Tippfehler könne
zum Fiasko führen, wenn aus Versehen ein Leerzeichen zuviel getippt
wird.
rm a* löscht beispielsweise alle Dateien, die mit "a" anfangen.
rm a * löscht dagegen erst die Datei "a" und dann alle Dateien
im Verzeichnis.
Anmerkungen:
"..." | Keine Ersetzung der Metazeichen * ? [ ], jedoch Ersetzung von
Shellvariablen (siehe unten) und Ersetzung durch die Ergebnisse von Kommandos
(Backquote). Auch \ funktioniert weiterhin. Dazu ein Beispiel:
echo Der * wird hier durch alle Dateinamen ersetzt echo "Der * wird hier nicht ersetzt" |
'...' | Das einfache Anführungszeichen unterdrückt jede
Substitution. Zum Beispiel:
echo 'Weder * noch `pwd` werden ersetzt' |
`...` | Zwischen Backquote (Accent Grave) gesetzte Kommandos werden ausgeführt
und das Ergebnis wird dann als Parameter übergeben (d. h. die Ausgabe des Kommandos
landet als Parameter in der Kommandozeile). Dabei werden Zeilenwechsel zu Leerzeichen.
Braucht dieses Kommando Parameter, tritt die normale Parameterersetzung in Kraft.
Zum Beispiel:
echo "Aktuelles Verzeichnis: `pwd`"
Weil die verschiedenen Quotes manchmal schwer zu unterscheiden sind, wurde bei der bash
eine weitere Möglichkeit eingeführt. Statt in Backquotes wird die Kommandofolge
in $( ... ) eingeschlossen., z. B.:
|
Weil die Backquotes relativ leicht zu übersehen sind, hat die bash von Linux eine alternative Schreibweise implementiert. Hier kann alternativ
$( ... )verwendet werden.
Beim Start liest die Bash eine Reihe von Konfigurationsdateien ein, interpretiert deren Inhalt und übernimmt bestimmte Einstellungen. Was dabei genau geschieht, hängt von mehreren Faktoren ab.
Ist die Bash als Login-Shell eingestellt, wird zunächst die Login-Konfigurationsdatei .bash_profile im Home-Verzeichnis des Anwenders gesucht. Ist sie vorhanden, führt die Bash die darin enthaltenen Befehle aus. Fehlt diese Datei, sucht die Bash im selben Verzeichnis nach einer Konfigurationsdatei mit dem Namen .bash_login. Fehlt auch diese, wird versucht, die systemweit gültige Konfigurationsdatei /etc/profile einzulesen und auszuwerten. Als letzte Möglichkeit versucht die Login-Bash, die Datei .profile im Home-Verzeichnis des Anwenders auszuführen.
Als interaktive (Sub-) Shell liest die Bash ihre Konfiguration aus der Datei .bashrc (im Home-Verzeichnis des Anwenders). Eine interaktive Bash verwendet für den Befehlszeileneditor zusätzlich die Einstellungen aus der Konfigurationsdatei .inputrc. Diese Datei wird zunächst im Home-Verzeichnis des Anwenders gesucht, ist sie dort nicht vorhanden, wird im Konfigurationsverzeichnis /etc/ nach der Datei inputrc gesucht.
Eine nicht interaktive (Sub-) Shell, wie sie zum Start von Skripten verwendet wird, liest keine Konfigurationsdateien ein, sofern dies nicht explizit gefordert wird.
Einige Versionen der Bash (z. B. die von SuSE Linux verwendete) suchen als interaktive Shell zunächst im Konfigurationsverzeichnis /etc/ nach systemweit gültigen Einstellungen in der Datei bash.bashrc. Diese ist aber normalerweise nicht vorhanden bzw. leer. Anschließend und unabhängig davon, ob diese Datei gefunden wurde, wird die persönliche Konfigurationsdatei .bashrc im Home-Verzeichnis des Anwenders eingelesen.
Damit bei einer Login-Shell auch Funktionen einer interaktiven Shell zur Verfügung stehen, wird am Ende der Login-Konfigurationsdatei oft auch die persönliche Konfigurationsdatei im Home-Verzeichnis des Anwenders eingelesen.
SuSE Linux löst die Konfiguration der Bash in folgender Weise: Die systemweite Konfiguration erfolgt in der Datei /etc/profile, an deren Ende weitere Konfigurationsdateien ausgeführt werden:
Auch beim Verlassen der Shell können von der Bash noch automatisch Befehle ausgeführt werden. Die Bash führt beim Eintreffen eines exit-Befehls die Datei .bash_logout im Home-Verzeichnis des Anwenders aus. Vorsicht: Nicht alle Versionen der Bash werten diese Datei korrekt aus.
Die Ausführung der Dateien läßt sich über zwei Kommandozeilen-Parameter steuern. Mit dem Parameter -noprofile veranlassen Sie, daß die Bash keine der oben genannten Startdateien ausführt, mit -norc erreichen Sie, daß die persönliche Konfigurationsdatei -/.bashrc ignoriert wird.
Codes für die Konstruktion des Prompts | |
---|---|
Code | Wirkung |
\a | Das Bell-Zeichen, wie es durch die Tastenkombination [Ctrl][g] erzeugt wird |
\d | das aktuelle Datum im Format Thu Jan 18 |
\e | das Escape-Zeichen |
\H | der gesamte (Host) -Name |
\h | der Rechner (Host) -Name bis zum ersten Punkt |
\n | ein Newline (LineFeed) -Zeichen |
\r | ein Return (Carriage Return) -Zeichen |
\s | der Programmname der Bash, also bash |
\t | die aktuelle Systemzeit im 24-Stundenformat HH:MM:SS |
\T | die aktuelle Systemzeit im 12-Stundenformat HH:MM:SS |
\@ | die aktuelle Systemzeit im 12-Stundenformat mit am/pm (01:39am) |
\u | der Username |
\v | die Version der ausgeführten Bash (2.03) |
\V | Das Release der Bash, bestehend aus der Versionsnummer und dem Patchlevel (2.03.1) |
\w | das aktuelle Arbeitsverzeichnis in ausführlicher Darstellung, beispielsweise ~/LinuxMagazin/bash/teil6 |
\W | der letzte Teil des aktuellen Verzeichnisses, etwa teil6 |
\! | die (History-) Nummer der aktuellen Befehlszeile |
\# | die Nummer der Befehlszeile in der aktuellen Bash-Sitzung |
\$ | mit diesem Schlüssen wird der Rootaccount gekennzeichnet. Wenn die effektive UID gleich Null ist, stellt die Bash das Hashmark dar, sonst ein Dollar-Zeichen |
\NNN | Jedes beliebige ASCII-Zeichen kann durch Eingabe des oktalen Codes nach einem Backslash erzeugt werden |
\\ | der Backslash selbst wird durch zwei Backslash-Zeichen erzeugt |
\[ | eine Folge von Steuerzeichen wird so eingeleitet |
\] | die Folge von Steuerzeichen wird so beendet |
Abhängig von der eingesetzten Terminalemulation können Sie Kombinationen mit der [Esc]-Taste oft auch mit der [Alt]-Taste nachgebilden. Statt also nacheinander [Esc] und [F] zu drücken, funktioniert meist auch die Kombination [Alt]+[F].
Die Anzahl der Befehlszeilen wird mit der Variablen HISTSIZE eingestellt. Wächst die History darüber hinaus, verwirft die Bash die ältesten Zeilen.
alias dir='ls -l' alias cd..='cd ..' alias md='mkdir' alias rd='rmdir' alias del='rm -i'Ohne Parameter gibt dieser Befehl eine Liste der aktuell definierten Aliasnamen aus. Zum Löschen eines Alias-Eintrags verwendet man den Befehl unalias Name.
Für den Administrator liefern Aliase weitere Unterstützung der täglichen Arbeit. Als Beispiel sollen hier nur drei Aliase dienen. Diese trägt man am Ende der Datei ".bashrc" im Heimatverzeichnis ein:
# sudo ist langweilig alias please='sudo' # zefix fuehrt letztes Kommando mit sudo aus alias zefix='sudo $(history -p \!\!)' # Weil ueberall der nano statt des vi hochpoppt alias argh='export EDITOR=vi'Beispiele für die Anwendung:
$ apt-get update E: Sperrdatei /var/lib/apt/lists/lock konnte nicht geöffnet werden - open (13: Permission denied) ... weitere Fehlermeldungen ... $ zefix OK http://de.archive.ubuntu.com precise Release.gpg OK http://de.archive.ubuntu.com precise-updates Release.gpg OK http://de.archive.ubuntu.com precise Release ...Oder auch richtig höflich:
$ please reboot Broadcast message from plate@blackhole (/dev/pts/0) at 12:08 ... The system is going down for reboot NOW! ...Was man jedoch nicht machen sollte:
$ rm -rf / ... $ zefix
Option | Name | Funktion |
---|---|---|
-a | allexport | neu definierte oder veränderte Variablen werden automatisch exportiert |
-b | notify | bewirkt, dass Meldungen von Hintergrundjobs sofort ausgegeben werden (voreingestellt wartet die Bash bis zur Ausgabe des nächsten Prompts) |
-B | braceexpand | Klammerexpandierungen erlauben (entspricht der Voreinstellung) |
-C | noclubber | Setzen dieser Option verhindert, dass bestehende Dateien durch Ausgabeumleitungen (Redirections) zerstört werden |
-e | errexit | In diesem Modus beendet sich die Shell immer dann automatisch, wenn ein Befehl einen Fehlercode erzeugte |
-f | noglob | Deaktiviert die Komplettierungsfunktion für Dateinamen |
-h | hashall | Deaktiviert das Speichern der Pfade bereits einmal ausgeführter externer Befehle; ein Abschalten bewirkt längere Ausführungszeiten bei Skripten |
-H | histexpand | Erlaubt erweiterte Ersetzungen aus dem Historybuffer (voreingestellt: on) |
-k | keyword | Zuweisungen werden in das Environment des Befehls übernommen |
-m | monitor | Aktiviert die Job-Kontrollfunktionen (Voreinstellung: on bei interaktiven Shells) |
-n | noexec | Verhindert die Ausführung von Befehlen; die Syntax wird aber überprüft und gegebenenfalls Fehlermeldungen erzeugt (deaktiviert bei interaktiven Shells) |
-o | Option | setzt die im Argument übergebene Option, siehe das Beispiel oben |
-p | privileged | Aktiviert den privilegierten Modus |
-P | physical | Unterdrückt die Darstellung von symbolischen Links, statt dessen wird das physikalische Verzeichnis verwendet |
-t | onecmd | Die Shell terminiert nach dem Ausführen des ersten Befehls |
-u | nounset | Bewirkt, dass ungesetzt Variablen Fehlermeldungen erzeugen; ohne diese Option wird ihnen ein leerer Inhalt zugewiesen |
-v | verbose | Befehlszeilen werden angezeigt, bevor sie ausgeführt werden |
-x | xtrace | Alle Befehlszeilen werden mit expandierten Argumenten angezeigt, bevor sie ausgeführt werden |
Mit der Einführung der Bash-Version 2.0 gibt es viele neue Konfigurations-Features. Sie werden durch den "erweiterten Konfigurationsbefehl" shopt gesetzt oder angezeigt. Die aktuellen Optionen sind über die Variable SHELLOPTS zugänglich. Der Befehl verfügt über folgende Optionen: -p (print) gibt eine Liste der aktuellen Einstellungen aus, -s (set) setzt die im Argument angegebene Option, -u (unset) löscht sie. Durch -q (quiet) wird die Ausgabe des Befehls unterdrückt, wie dies in Skripten praktisch sein kann. Durch -o beschränkt sich die Wirkung von shopt auf die durch set -o gesetzten Optionen. In der folgenden Tabelle sind nur die wichtigsten mittels shopt einstellbaren Bash-Optionen aufgeführt, eine vollständige Liste enthält die Manual-Page.
Option | Funktion |
---|---|
cdable_vars | bewirkt, dass die Bash Argumente des cd-Befehls als Variablen interpretiert, wenn es sich um keine Verzeichnisse handelt |
cdspell | einfache Schreibfehler (vertauschte oder fehlende Buchstaben) in Verzeichnisnamen werden durch diese Option automatisch korrigiert |
checkhash | die Bash sucht einen externen Befehl zunächst in der Hashtabelle, bevor er anhand des Suchpfades gefunden wird |
checkwinsize | wenn diese Option aktiviert ist, prüft die Bash nach jedem ausgeführten Befehl, ob sich die Terminal-Abmessungen geändert haben. |
cmdhist | zusammengehörige Befehlszeilen werden in der History in Form einer Zeile abgelegt, dadurch vereinfacht sich ihre Bearbeitung |
dotglob | durch das Setzen dieser Option werden auch die mit einem Punkt beginnenden Dateinamen beim automatischen Komplettieren berücksichtigt |
execfail | verhindert in Skripten, dass die Shell nach einem Fehler in einem exec-Befehl terminiert |
histexpand | bewirkt, dass Historydateien nicht mehr überschrieben, sondern an bestehende Dateien angehängt werden |
lithist | zusammen mit cmdhist bewirkt sie das Zusammenfassen mehrzeiliger Befehle |
sourcepath | der source-Befehl kann auf die PATH-Variable zugreifen, wenn diese Option gesetzt ist |
expand_aliases | erlaubt das Expandieren von Alias-Definitionen |
nocaseglob | bei der automatischen Dateinamenkomplettierung berücksichtigt die Bash Groß-/Kleinschreibung nicht, wenn diese Option aktiv ist |
huponexit | allen von einer interaktiven Shell ausgeführten Hintergrundjobs wird ein SIGHUP-Signal gesendet, wenn sie terminiert |
restricted_shell | die Bash wird im Restricted-Modus mit eingeschränkter Funktionalität betrieben |
$((Ausdruck))Diese Konstruktion wird dann folgendermaßen verwendet:
VAR=$((Ausdruck))Zum Beispiel:
$ echo $(( 9 * 3 )) 27 $ X=$(( 2* 3 + 5 )) $ echo $X 11Als Operationen wird nahezu alles geboten, was auch in der Sprache C vorhanden ist:
Operator | Bedeutung |
---|---|
wert++ | Postinkrement der Variablen |
wert-- | Postdekrement der Variablen |
++wert | Präinkrement der Variablen |
--wert | Präiekrement der Variablen |
+ - | Plus und Minus |
! ~ | Logische und Bitweise Negation |
* / % | Mal, Teilen und Modulo |
<< >> | linkes und rechtes bitweises Verschieben |
<= >= < > | Vergleichsoperatoren |
== != | Gleich und Ungleich |
& ^ | | Bitweises UND, exklusives ODER und ODER |
&& || | Logisches UND und ODER |
AUSDR1?AUSDR2:AUSDR3 | Ergebnis: Wenn AUSDR1 dann AUSDR2 sonst AUSDR3 |
Es gibt nur einen Fallstrick: Wie bei C werden Zahlen mit führenden Nullen als Oktalzahlen (Basis 8) interpretiert. In folgenden Beispiel gibt es zum Glück eine Fehlermeldung:
$ echo $(( 09 * 3 )) -bash: 09: Der Wert ist zu groß für die aktuelle Basis. (Fehlerverursachendes Zeichen ist \"09\").Aber das muss nicht immer so sein, so ist 27 nicht gleich 027:
# dezimal $ echo $(( 27 * 3 )) 81 # oktal $ echo $(( 027 * 3 )) 69Und denken Sie daran, dass es sich um Ganzzahl-Arithmetik mit begrenztem Wertebereich habdelt.
${var:start:anzahl} ${var:start}Damit schneiden Sie aus der Variablen var ab der Position start, anzahl Zeichen heraus. Fehlt die Angabe anzahl, wird von der Position start bis zum Ende kopiert. Zum Beispiel:
S=0123456789 echo ${S:3:4} 3456 echo ${S:3} 3456789 T=${S:3:5} echo $T 34567
Arrays ermöglichen es, eine geordnete Folge von Werten eines bestimmten Typs zu speichern und zu bearbeiten. Allerdings erlaubt die Bash nur eindimensionale Arrays mit einem ganzzahligen positiven Index. Das erste Element eines Arrays hat immer den Index 0. Oft werden Arrays in Schleifen verwendet. Hier muss man dann nicht auf eine Reihe von einzelnen Variablen zurückzugreifen.
Wenn Sie einer Array-Komponenten einen Wert zuweisen wollen, geben Sie den Feldindex an:
# Belegen der dritten(!) Arraykomponente mit dem String "zwo" array[2]=zwoWas geschieht in diesem Fall mit den Komponenten array[0] und array[1]? Bei der Bash-Programmierung dürfen Arrays Lücken enthalten (wie z. B. auch in Perl). Im Unterschied zu anderen Programmiersprachen müssen Sie in der Bash das Array nicht vor der Verwendung deklarieren. Sie sollten es jedoch trotzdem zu tun, denn einerseits kann man damit angeben, dass die Werte innerhalb eines Arrays als Integer gültig sein sollen (typeset –i array) und andererseits können Sie ein Array mit Schreibschutz versehen (typeset –r array).
Häufig will man beim Anlegen eines Arrays dieses mit Werten initialisieren. In der Bash geschieht dies durch Klammern der Werte:
array=(Merkur Venus Erde Mars Jupiter Saturn Uranus Neptun ...)Bei der Zuweisung beginnt der Feldindex automatisch bei 0, also enthält array[0] den Wert "Merkur". Aber ist es auch möglich, eine Zuweisungsliste an einer anderen Position zu beginnen, imdem der Startindex angegeben wird:
array=([2]=Pluto Eris ...)Diese Methode ist jedoch nicht geeignet, an ein Array neue Elemente anzuhängen. Ein existierendes Array wird immer komplett überschrieben. Die Anzahl der Elemente, die Sie einem Array übergeben können, ist bei der Bash beliebig. Als Trennzeichen zwischen den einzelnen Elementen dient das Leerzeichen.
Der Zugriff auf die einzelnen Komponenten eines Arrays erfolgt mit
${array[index]}Für die Referenz auf den Arrayinhalt müssen geschweifte Klammern verwendet werden, da die eckigen Klammern ja schon Metazeichen der Bash sind (Bedingung analog dem test-Kommando) und sonst eine Expansion auf Shell-Ebene versucht würde.
Alle Elemente eines Arrays können Sie, ähnlich wie bei den Kommandozeilenparametern, folgendermaßen ausgeben lassen:
echo ${array[*]} echo ${array[@]}Der Unterschied ist der gleiche wie bei den Kommandozeilenparametern ($* und $@). Mit ${!arr[*]} lassen sich alle Indizes des Arrays auflisten. Dieses Feature ist erst später hinzugekommen. Diese Liste ist interessant, wenn das Array Lücken bei den Indizes aufweist. Im folgenden Beispiel werden Index und Inhalt aufgelistet:
for IND in ${!array[@]} do echo "$IND ${array[$IND]}" done
Die Anzahl der belegten Elemente im Array erhalten Sie mit (auch diese Syntax ähnelt der Kommandozeile bzw. der Shell-Variablen $#):
echo ${#array[*]}Wollen Sie feststellen, wie lang eine Array-Komponente ist, so gehen Sie genauso vor wie beim Ermitteln der Anzahl belegter Elemente im Array, nur dass Sie anstelle des Sternchens den entsprechenden Feldindex verwenden:
echo ${#array[1]}Beispiele:
array=(Merkur Venus Erde Mars Jupiter Saturn Uranus Neptun) echo ${array[4]} Jupiter echo ${#array[*]} 8 echo ${#array[2]} 4Es lassen sich auch Teile eines Array selektieren. So liefern die folgenden Ausdrücke:
${array[@]} # das gesamte Array (s. oben) ${array[@]:index:length} # die Array-Komponenten von 'index' bis 'index+length-1' inklusive ${array[@]::length} # die Array-Komponenten von '0' bis 'length-1' inklusive ${array[@]:index} # die Array-Komponenten von 'index' bis zum EndeBeispiele:
array=(Merkur Venus Erde Mars Jupiter Saturn Uranus Neptun) echo "${array[@]:2}" Erde Mars Jupiter Saturn Uranus Neptun echo "${array[@]:1:3}" Venus Erde Mars echo "${array[@]::1}" MerkurZum Löschen eines Arrays oder einer Komponente wird wie bei den Shell-Variablen vorgegangen. Das komplette Array löschen Sie mit:
unset arrayEinzelne Elemente können Sie folgendermaßen löschen:
unset array[index]Das funktioniert aber nicht immer, zum Beispiel:
INDEX=4 echo "${array[$INDEX]}" Jupiter unset ${array[$INDEX]} echo "${#array[@]}" 8 # sollte aber nun '7' sein, weil Jupiter geloescht wurde echo "${array[$INDEX]}" Jupiter # Ooops!Der Fehler liegt darin, dass in der Bash ein Array als sogenannter Hash gespeichert wird ("sparse"). Also nicht darauf verlassen, dass eine Komponente nach dem unset tatsächlich weg ist.
Zum Kopieren eines kompletten Arrays können Sie entweder eine Schleife programmieren, in der jedes einzelne Element einem anderen Array zugewiesen wird. Es geht aber auch mit weniger Aufwand. Sie kombinieren das Auflisten aller Elemente des einen Arrays mit dem Zuweisen einer Liste mit Werten an ein zweites Array:
array_neu=( ${array[@]} )Beispiel:
array=(Merkur Venus Erde Mars Jupiter Saturn Uranus Neptun) echo ${array[@]} Merkur Venus Erde Mars Jupiter Saturn Uranus Neptun yarra=( ${array[@]} ) echo ${yarra[@]} Merkur Venus Erde Mars Jupiter Saturn Uranus Neptun
Auch für die Ausgabe gibt es zwei Möglichkeiten:
![]() |
![]() |