Bash-Skripte erstellen - Die Shell als Programmiersprache


Jede Anwendung der hier beschriebenen Hinweise und Tips erfolgt ausschließlich auf eigene Gefahr. Keine Haftung für die Richtigkeit der Darstellung. Jegliche Haftung für irgendwelche Schäden aufgrund dieses Textes ist ausgeschlossen.


Inhalt:


1. Über Bash

Shells sind Kommandozeileninterpreter. Bash, die "Bourne Again shell", ist die erweitere Open-Source-Variante der Shell "sh", die Stephen Bourne in den 70er Jahren für das Betriebssystem Unix entwickelt hat.
Unter Linux ist Bash wohl am weitesten verbreitet, auch wenn andere Shells wie "sh", "ksh", "csh" und "tcsh" ebenfalls zur Verfügung stehen.

Bei der Shell-Programmierung erfolgt die Datenverarbeitung anders als in anderen Programmiersprachen in der Regel dadurch, daß die Ausgabe eines Befehls einem oder mehreren anderen Befehlen zur Weiterverarbeitung zugeführt wird.
Man verwendet die Shell-Befehle dann also wie mehrere Werkzeuge eines Werkzeugkastens.
Es gibt aber auch Kontrollstrukturen wie in anderen Programmiersprachen.

Bash-Skripte werden vor allem zur Automatisierung von Betriebssystemvorgängen oder zur Durchführung von Programminstallationen verwendet. Nachteile sind, daß sie nicht allzu schnell ablaufen und außerdem wenig portabel sind. Zudem sind sie für Menschen oft schlecht lesbar.


2. Grundlagen. Umleitung von Befehlsausgaben

Als Kommandozeileninterpreter sucht Bash in einer Zeile nach einem Befehl und den dazu gehörenden Optionen.

Die Befehle sind wie bei Basic oder DOS englische Wörter, die jedoch erheblich verkürzt sind, um nicht so viel tippen zu müssen.
Die Linux-Befehle unterscheiden sich erheblich von DOS, auch wenn sie dasselbe tun.

Ein Bash-Befehl wäre z.B.

echo "Hallo Welt"

Im Gegensatz zu DOS beachtet Bash Groß- und Kleinschreibung (= case sensitive).

Die Shell versucht, alle angefangenen Eingaben automatisch zu vervollständigen, wenn man jeweils TAB eingibt.

Mit den Cursortasten kann man vorherige Eingaben wieder zurückholen.

Es gibt drei sogenannte Datenkanäle STDIN, STDOUT und STDERR, die von Programmen verwendet werden können:

STDIN ist der Standardeingabekanal. Er ist standardmäßig mit der Tastatur verbunden. Das bedeutet, wenn ein Programm Daten aus diesem Kanal zu lesen versucht, wartet es auf Tastatureingaben.

Der Standardausgabekanal STDOUT ist dagegen standardmäßig mit dem Bildschirm verbunden. Schreibt ein Programm Daten in diesen Kanal, erscheinen sie also gewöhnlich auf dem Bildschirm. Auf diese Weise arbeitet auch "echo": Es sendet das erhaltene Argument (oben "Hallo Welt") an STDOUT.

Der Kanal STDERR ist für Fehlermeldungen gedacht. Er ist standardmäßig ebenfalls mit dem Bildschirm verbunden.

In Bash kann man die Ausgabe von Befehlen statt nach STDOUT aber auch in eine Datei leiten. Dazu verwendet man die Zeichen ">" und ">>".

So erscheint bei

echo "Hallo Welt" > hallo.txt

nichts auf dem Bildschirm. Stattdessen findet sich die Ausgabe in der Datei "hallo.txt" im aktuellen Verzeichnis.

echo "Hallo Welt" >> hallo.txt

fügt dieser Datei noch einmal "Hallo Welt" an. Mit

cat hallo.txt

kann man sich den Inhalt der Datei "hallo.txt" anschauen.

Etwas Vorsicht ist bei der Umleitung mit ">" geboten: Sollte bereits eine Datei mit dem Namen der Ausgabedatei existieren, so wird sie ohne Warnung mit der Befehlsausgabe überschrieben. Das Problem ist bei ">>" geringer: Hier wird der Datei lediglich etwas angehängt, so daß es gegebenenfalls nachträglich wieder entfernt werden kann.

Ausgaben von Befehlen können aber nicht nur in Dateien geleitet werden, sondern auch in den Eingabekanal anderer Befehle.
Dazu verwendet man das Zeichen "|" (auf der Tastatur: "AltGR + <"). Ein Beispiel:

ls

zeigt die Namen der Dateien im aktuellen Verzeichnis über STDOUT auf dem Bildschirm an. Sind sehr viele Dateien in einem Verzeichnis, scrollt "ls" den Inhalt zu schnell nach oben. Mit

ls | less

kann man sich die Ausgabe von "ls" mit dem Tool "less" bildschirmweise anzeigen lassen.
Die Umleitung der Ausgabe eines Befehls in einen anderen mittels "|" (man nennt dies das Erstellen einer "Pipe") führt also zu einer Weiterverarbeitung der Daten durch den zweiten Befehl.

Die Ausgabeumleitung mit ">", ">>" und "|" gibt es übrigens auch unter DOS.


3. Bash-Skripte erstellen und ausführen

Man kann mit einem Editor (wie "vim", "emacs", "kate", "gedit", "joe" etc.) eigene Skripte erstellen. Das sind Dateien, die beliebig viele hintereinander auszuführende Konsolenkommandos enthalten (vergleichbar "autoexec.bat" unter DOS; die hier beschriebenen Bash-Skripte sollen aber nicht automatisch beim Systemstart ausgeführt werden).
Die erstellten Skripte kann man dann unter Linux, wenn man die nötigen Benutzerrechte hat und mit

chmod +x skript

das Attribut "ausführbar" für das Skript gesetzt hat, ausführen. Dies geht entweder mit einem erneuten Aufruf der Shell, also mit

bash skript

oder man führt das Skript ohne erneuten Aufruf der Shell aus. Ist das Skript im aktuellen Verzeichnis und ist dieses nicht in "$PATH" enthalten, muß man dazu aber noch angeben, daß man sich auf das aktuelle Verzeichnis bezieht. Dieses wird durch "." symbolisiert.
Zum Aufruf des Skripts im aktuellen Verzeichnis gibt man dann also

./skript

ein.

Man kann die Skripte dann in dem Verzeichnis

/usr/local/bin

ablegen. Da vom System für dieses Verzeichnis bereits standardmäßig die Variable "$PATH" gesetzt ist, lassen sich die Skripte dann von jedem Verzeichnis aus ausführen.

Es ist sinnvoll, in dem Skript anzugeben, daß es mit Bash ausgeführt werden soll. Dazu gibt man in der ersten Zeile des Skripts an:

#!/bin/bash

Diese erste Zeile im Skript nennt man "sh'bang": "sh'" steht für sharp (#), "bang" für das Ausrufezeichen.

Erstellt man also etwa eine solches Skript mit dem Inhalt

#!/bin/bash
echo "Hallo Welt"

nennt es "mine", setzt die Benutzerrechte auf "ausführbar" ("chmod +x mine") und bringt es nach "/usr/local/bin"("cp ./mine /usr/local/bin"), kann man von jedem Verzeichnis aus einfach "mine" eingeben, um das Skript zu starten.


4. Expansion der Kommandozeile durch die Shell

Als Kommandozeileninterpreter sucht Bash in einer Zeile nach einem Befehl und den dazu gehörenden Optionen.
Vor der Ausführung des Befehls werden aber zudem noch bestimmte Sonderzeichen wie etwa "*" in der Zeile

cp * /home/user

ausgewertet. Diese Auswertung, bzw. Expansion erfolgt auch in Programmzeilen in Skripten.
Daher muß man gelegentlich aufpassen, zu was genau die Shell eine Programmzeile vor der jeweiligen Ausführung auswertet.

Die Optionen, bzw. Parameter der Shell-Befehle werden in der Regel durch Leerzeichen voneinander getrennt, z.B. in "ls -l -i -s -a".
Verwendet man Ausdrücke, die zu Befehlsparametern ausgewertet werden sollen, muß man also darauf achten, daß bei der Ausdrucksauswertung keine überschüssigen Leerzeichen entstehen, die sonst als Ende des jeweiligen Parameters gedeutet würden.

Setzt man Strings in einfache Anführungszeichen, z.B.

echo 'Hallo *'

deutet die Shell den Ausdruck trotz Leerzeichen als einheitliche Zeichenkette. Zudem erfolgt keine Expansion der gegebenenfalls enthaltenen Sonderzeichen (hier "*").

Setzt man Strings in doppelte Anführungszeichen, z.B.

echo "Hallo *"

so handelt es sich ebenfalls um eine einheitliche Zeichenkette. Die meisten Sonderzeichen werden nicht expandiert, einige aber doch, insbesondere "$", so daß z.B. der Inhalt einer Variablen "$a" in

a=Welt; echo "Hallo $a"

(zu Variablen siehe sogleich) Teil der Zeichenkette wird.


5. Variablen

Die Skalarvariablen in Bash sind grundsätzlich Strings. Man definiert sie nur mit ihrem Variablennamen. Um später auf sie zuzugreifen, muß man ein "$" davorsetzen. Die Shell wertet dann den Variablennamen zum Inhalt der Variablen aus:

#!/bin/bash

a="Hallo Welt !"
echo $a

Diese Variablenexpansion erfolgt in jeder einzelnen Zeile des Skripts.

In der Zeile a="Hallo Welt !"

darf kein Leerzeichen zwischen "a", "=" und dem folgenden Wert stehen. Denn Leerzeichen trennen in Bash Anweisungen (wie z.B. Shell-Befehle) von Parametern (wie Befehlsoptionen (wie z.B. in "ls -l")). Nur wenn das Gleichheitszeichen in Verbindung mit den Variablennamen und -werten ohne Leerzeichen verwendet wird, kann die Shell erkennen, daß es sich um eine Variablenzuweisung handeln soll.
 


6. Zuweisung der Ausgabe von Befehlen zu Variablen durch Expansion

Es wurde bereits dargestellt, daß die Ausgabe von Befehlen mittels "|" anderen Befehlen über deren Dateneingabekanal zur Weiterverarbeitung zugeleitet werden kann ("Pipe").

Doch wie weist man einer Variablen die Ausgabe eines Befehls zu ? Variablen haben ja keine Dateneingabekanäle.

Dazu setzt man Befehle in sog. Backticks (`) (auf der Tastatur: "Shift + Taste rechts neben dem ?") oder zwischen mit "$" versehene runde Klammern, also:

$(Befehl)

Dann wird der Befehl ausgeführt und seine Ausgabe zu einem Ausdruck innerhalb der Befehlszeile ausgewertet. Dieser Ausdruck kann dann einer Variablen zugewiesen werden:

#!/bin/bash

a=$(ls -la)
echo $a

Oft ist es sinnvoll, den ausgewerteten Ausdruck nochmals von Anführungszeichen zu umschließen, um klarzustellen, daß es sich bei diesem trotz enthaltener Leerzeichen um einen einzigen zusammengehörenden Ausdruck und nicht um einzelne Wörter oder Zahlen handelt.


7. for-Schleifen im "C-Stil"

In BASIC kann man Folgendes machen:

10 FOR i=1 TO 10
20 PRINT i
20 NEXT i

Das geht auch in Bash:

#!/bin/bash

for ((i=1; i<=10; i++))
do
    echo $i
done

for-Schleifen kann man (fast wie in der Sprache C) nach obigem Muster konstruieren: Zwischen zwei runde Klammmern schreibt man, jeweils durch Semikolon getrennt, drei Dinge:

  1. Man weist der Schleifenvariablen einen Wert zu, mit dem die Schleife beginnen soll.
  2. Man definiert eine Bedingung. Die Schleife läuft solange, wie diese Bedingung erfüllt ist.
  3. Man bestimmt, in welcher Weise die Schleifenvariable nach einem Schleifendurchlauf verändert wird.
    "i++" ist dabei die Kurzform für "i=i+1".

Sodann schreibt man zwischen die Zeilen "do" und "done", welche Anweisungen während des Schleifendurchlaufs ausgeführt werden sollen.

Die Einrückung der Anweisungen in Anweisungsblöcken (wie z.B. oben um jeweils vier Leerzeichen) ist in Bash (anders als in Python) nicht unbedingt erforderlich, wird aber empfohlen, da dadurch die Lesbarkeit des Codes etwas erhöht wird.

Die Anweisung "break;" innerhalb eines Anweisungsblocks bewirkt den vorzeitigen Abbruch der Schleife. Das Programm wird dann unmittelbar nach der Schleife fortgesetzt. "break 2" bricht dabei zwei ineinander verschachtelte Schleifen gleichzeitig ab.

Die Anweisung "continue;" innerhalb des Anweisungsblocks bewirkt, daß die Schleife vorzeitig den nächsten Durchlauf startet, ohne daß die nach "continue;" folgenden Anweisungen noch ausgeführt werden.


8. for-Schleifen im "Python-Stil"

Noch gebraüchlicher sind in Bash for-Schleifen, in denen die Schleifenvariable jeweils eines der nach dem Wort "in" folgenden Argumente repräsentiert:

#!/bin/bash

a="Geh Du alter Esel, hol Fisch." 
for i in $a 
do
    echo $i
done

In der dritten Zeile wird $a zu den Wörtern expandiert, und zwar ohne Anführungszeichen. $i steht dann jeweils für eines dieser Wörter.
Benutzt man in dem Skript oben stattdessen die Zeile

for i in "Geh Du alter Esel, hol Fisch."

so steht $i für den ganzen String, und die Schleife wird nur einmal durchlaufen.


9. while-Schleifen. "a = a + 1" erreichen

Neben for-Schleifen bietet Bash noch while-Schleifen, mit denen man das Programm für die Schleife von 1 bis 10 ebenfalls schreiben kann:

#!/bin/bash

i=1

while test $i -le 10
do
    echo $i
    let "i += 1"
done

Die Bedingung für die while-Schleife wird mit dem Befehl "test" erzeugt; Näheres siehe "man test".

Um "i = i + 1" zu erreichen, benutzt man die Zeile oben:

let "i += 1"

Dabei sind besonders die Leerzeichen zu beachten. Sie müssen genau so wie gezeigt geschrieben werden.
Um eine Variable um eins zu erhöhen, kann auch "let i++" verwendet werden.

Es gibt auch noch den Befehl:

i=$(expr $i + 1)

Aber der "let"-Befehl ist wesentlich schneller. Er ist Teil von bash ("builtin").

Will man das Skript mit der while-Schleife in der Shell interaktiv in einer Befehlszeile ausführen, müssen alle Befehle mit ";" abgetrennt werden. Allerdings darf dabei zwischen "do" und dem folgenden Befehl kein ";" stehen:

i=1; while test $i -le 10; do echo $i; let "i += 1"; done


10. if-Bedingungen

BASIC:

10 LET a=1
20 IF a=1 THEN PRINT "a=1"
30 IF a<>2 THEN PRINT "a ist nicht 2."
40 IF a=2 THEN PRINT "a=2" ELSE PRINT "a ist nicht 2."
50 LET b=2
60 IF a=1 AND b=2 THEN PRINT "a=1, b=2"
70 IF a=1 OR b=2 THEN PRINT "a=1 oder b=2."

Bash:

#!/bin/bash

a=1
if [ $a -eq 1 ];
then
    echo "a=1"
fi
if [ $a -ne 2 ];
then
    echo "a ist nicht 2."
fi
if [ $a -eq 2 ];
then
    echo "a=2."
else
    echo "a ist nicht 2."
fi
b=2
if [ $a -eq 1 ] && [ $b -eq 2 ];
then
    echo "a=1, b=2."
fi
if [ $a -eq 1 ] || [ $b -eq 2 ];
then
    echo "a=1 oder b=2."
fi

Wie man sieht, ist die Form für if-Bedingungen:

if <test-Befehl-mit-Ausdruck>; then <Anweisungen>; else <Andere-Anweisungen>; fi

Der Ausdruck

[  ]
ist eine Kurzform für den Befehl "test" (siehe "man test"). Dabei sind die Leerzeichen rechts, bzw. links innerhalb der eckigen Klammern unbedingt erforderlich.

Neben "else" gibt es noch "elif" (für "else if").


11. Eingaben

BASIC:

10 LET a=0
20 INPUT a
30 PRINT a

Bash:

#!/bin/bash

a=0
read a
echo $a

So wie "echo" eine Zeile nach STDOUT ausgibt (s.o.), liest "read" standardmäßig eine Zeile von STDIN.


12. Beispielskript "Krümelmonster"

Nachdem wir Schleifen, Eingaben und Bedingungen kennengelernt haben, können wir diese Programmiertechniken einmal verbinden.

Bitte finden Sie selbst heraus, was das folgende Skript tut und wie es es tut:

#!/bin/bash

kekse=""
while test -z $kekse || test $kekse != "KEKSE"
do
    echo -n "Ich will KEKSE: "
    read kekse
done
echo "Mmmm. KEKSE."

Das "||" in der while-Zeile steht für logisches ODER. Die zweite "test"-Prüfung in der while-Zeile wird nur ausgeführt, wenn nicht schon die erste Bedingung ($kekse gleich "") erfüllt ist.

Die erste Überprüfung ist notwendig, denn wenn $kekse gleich "" ist, würde $kekse zu nichts expandiert, so daß "test" für andere Vergleiche als für die Optionen "-z" und "-n", also etwa für "!="-Überprüfungen kein brauchbares Argument erhielte.


13. Optionen der Befehle verarbeiten - Positionsparameter

Das Skript kann mit Optionen aufgerufen werden, z.B.

./skript -a

Die Optionen wie "-a" werden in besonderen Variablen, "$1", "$2", "$3", usw. gespeichert, die so innerhalb des Skripts verarbeitet werden können. "$@" enthält alle erkannten Optionen in einem String. Die Anzahl der jeweils durch ein Leerzeichen getrennten Optionen kann über "$#" abgefragt werden.

In dem Beispiel oben enthält also "$1" im Skript den Ausdruck "-a".


14. Stringverarbeitung

Die Verarbeitung von Strings ist in Bash weniger komfortabel als in anderen Programmiersprachen.

Die Anzahl der Zeichen einer Variablen $a erhält man mit "${#a}".

"${a:2:3}" liefert einen Substring von 3 Zeichen ab Position 2 in der Variablen $a. "${a:2}" liefert alle Zeichen von Position 2 bis zum Ende.

a=${a/from/to}

ersetzt das erste Vorkommen von "from" in der Variablen $a zu "to".

a=${a//from/to}

ersetzt jedes Vorkommen von "from" in der Variablen $a zu "to".


15. Arrays

Arrays (Feldvariablen) sind in Shell-Skripts traditionell weniger gebräuchlich, werden aber in neueren Versionen von Bash durchaus unterstützt.

Mehrere Array-Elemente können gemeinsam zugewiesen werden, den Array-Stellen können aber auch direkt Werte zugewiesen werden.
Die erste Array-Stelle beginnt bei 0 (wie in den meisten anderen Programmiersprachen auch).
Die Anzahl der Array-Elemente kann ermittelt werden. Arrays können durchlaufen werden:

#!/bin/bash

arr=("Apfel" "Birne" "Pfirsich")

arr[3]="Banane"
arr[4]="Kirsche"

echo
echo "Das Array hat ${#arr[@]} Elemente:"
echo
 
for ((i=0; i<${#arr[@]}; i++))
do
    echo ${arr[$i]}
done

echo


16. Funktionen

Für komplexere Skripte bietet Bash auch Funktionen. Allgemein sind das Unterprogramme, die Daten als Argumente erhalten und Ergebnisse zurückgeben können. Auf diese Weise können umfangreiche Aufgaben in viele kleine Teilaufgaben zerlegt werden:

#!/bin/bash

selfdefinedfunction ()
{
    echo $1
}

selfdefinedfunction "Hallo" 

Der Aufruf von "selfdefinedfunction" mit dem Parameter "Hallo" bewirkt, daß innerhalb der Funktion die Variable "$1" diesen Parameter enthält.

Lokale Variablen können innerhalb der Funktion mit dem Befehl "local" definiert werden.

Von der Shell aufgerufene Unterprozesse und eben auch Funktionen können einen Rückgabewert zurückliefern. Auf diesen kann über die Variable "$?" zugegriffen werden. Eigentlich ist das für Programme gedacht, die so z.B. melden, ob sie erfolgreich beendet wurden. Aber auf diese Weise können auch Funktionen in Bash-Skripten Werte zurückgeben:

#!/bin/bash

selfdefinedfunction ()
{
    echo $1
    return 5
}

selfdefinedfunction "Hallo" 
echo $?


17. Umleitung von Datenkanälen

Manchmal möchte man nicht, daß z.B. Fehlermeldungen eines Programms auf dem Bildschirm ausgegeben werden.
Dies kann man durch Umleitung des Kanals STDERR verhindern:

So kann man Ausgaben also auch nach "/dev/null", das heißt ins Nichts leiten:
echo "gone" &>/dev/null


18. Sonderproblem: Mehrzeilige Variablen in einer Schleife verarbeiten

In Shell-Variablen wird das Neue-Zeile-Zeichen durch Ersetzung von

$'\n'

erzeugt. Eine mehrzeilige Variable definiert man also z.B. durch:

#!/bin/bash

a="Zeile1"$'\n'"Hallo Welt"$'\n'"Zeile3"
echo "$a"

Da die Shell bei for-Schleifen im "Python-Stil" den nächsten Schleifendurchlauf bei einem Leerzeichen beginnt, kann man mit folgendem Skript aber nicht jede Zeile der Variablen a durchlaufen:

#!/bin/bash

a="Zeile1"$'\n'"Hallo Welt"$'\n'"Zeile3"
for i in $a 
do
    echo $i
done

Denn hier wird die Schleife ungewollt auch zwischen "Hallo" und "Welt" durchlaufen, so daß "Hallo" und "Welt" in zwei verschiedenen Zeilen ausgegeben werden.
Es geht auch nicht mit Anführungszeichen wie in folgendem Skript:

#!/bin/bash

a="Zeile1"$'\n'"Hallo Welt"$'\n'"Zeile3"
for i in "$a"
do
    echo "$i"
done
echo "$i"

Denn hier wird $i sofort der ganze Inhalt der Variablen $a zugewiesen und nicht nur die jeweilige Zeile von $a.
Dies zeigt die letzte Ausgabe von $i nach der Schleife. Diese wurde insgesamt nur einmal durchlaufen.

Um jede Zeile von $a einzeln zu verarbeiten, benötigt man vielmehr folgende Konstruktion:

#!/bin/bash

a="Zeile1"$'\n'"Hallo Welt"$'\n'"Zeile3"
echo "$a" | while read i
do
    echo $i
done

Dabei wird der Inhalt der Variablen $a über eine Pipe zeilenweise in eine while-Schleife geleitet, in der mit Hilfe von read die einzelnen Zeilen solange der Variablen $i zugewiesen werden, bis $a keine Zeilen mehr liefert.


19. Verarbeitung von Daten in Textdateien: awk, grep, sed; Unterstützung von Perl

Im Grundsatz ist Bash mehr auf den Umgang mit ganzen Dateien und Verzeichnissen als auf die Verarbeitung von Daten in Dateien ausgelegt.

Um bestimmte Zeilen aus Textdateien (oder Befehlsausgaben) herauszusuchen, kann man den Befehl "grep" verwenden.
Ruft man "grep" mit einem Suchwort und einem Dateinamen auf, so wird die angegebene Datei nach dem Suchstring durchsucht, und die gefundenen Zeilen werden ausgegeben. Der Befehl

grep -i wort datei.txt

durchsucht also die Datei "datei.txt" nach Zeilen, die den Begriff "wort" enthalten (wobei im Beispiel wegen der "grep"-Option "-i" Groß-/Kleinschreibung ignoriert wird) und gibt die gefundenen Zeilen aus.
"grep" wird auch oft in einer Pipe verwendet wie in "cat datei.txt | grep wort" oder "find | grep html".

Hat man mit "grep" bestimmte Zeilen gefunden, möchte man diese oft zerteilen, weil einen nur bestimmte Teile innerhalb dieser Zeile interessieren. Hierzu kann man "awk" verwenden:

Angenommen, eine Textdatei "datei.txt" enthält eine Zeile mit dem Inhalt:

Anton;Berta;Cäsar;Dora;Emil

Dann gibt

grep Berta datei.txt

diese Zeile aus. Um die Zeile zu zerteilen, muß "awk" einen Input erhalten, gesagt bekommen, bei welchem Zeichen die Trennung vorgenommen werden soll und was es mit dem Ergebnis tun soll. Folgender Befehl gibt in dem Beispiel das Teilstück "Anton" aus:

grep Berta datei.txt | awk -F ";" '{print $1}'

Das Trennzeichen für "awk" wird also mit der Option "-F" angegeben und die speziellen awk-Bearbeitungsbefehle für die Textteile (z.B. "print") in geschweifte Klammern gesetzt, die in einfachen Anführungszeichen eingeschlossen werden.

Änderungen in Textdateien kann man theoretisch mit dem Stream-Editor "sed" ("man sed") vornehmen.

Das alles wird aber ziemlich unkomfortabel. Daher setzt man für solche Operationen stattdessen häufig die Programmiersprache Perl ein.

Einzeilige Perl-Skripte lassen sich auch von Bash-Skripten aus aufrufen. So kann mit

perl -e 'print "Hello World\n";'

Text über Perl ausgegeben werden. Typischerweise wird aber in Bash-Skripten die Ausgabe eines Shell-Befehls in einen Perl-Einzeiler geleitet:

echo "Hello World" | perl -e 'while(<>){$_ =~ s/World/Planet/g; print $_;}'

In dem Beispiel wird die Ausgabe von "echo" durch Perl verändert und dann wiederum ausgegeben.
Die Perl-Konstruktion "while(<>){}" liest dabei solange Zeilen von STDIN, bis dort keine mehr ankommen.

Das "awk"-Beispiel oben mit "Anton" und "Berta" sähe mit Perl dann z.B. so aus:

grep Berta datei.txt | perl -e 'while(<>){@a = split(";"); print $a[0]."\n"}'


20. Weiterführende Links

Bash Guide for Beginners  Entgegen dem Wortlaut des Titels ein ziemlich ausführliches Handbuch.
Advanced Bash-Scripting Guide  Ein sehr gutes Nachschlagewerk für Einzelfragen.
 
Zurück


Autor: hlubenow2 {At-Zeichen} gmx.net