Shell-Skripte verrichten unter Linux allgegenwärtig ihren Dienst. Mit Bashdiff erhält die Standard-Shell Features, die Sie sonst nur in höheren Programmiersprachen finden.
Haben Sie auch schon einmal Shellskript geschrieben und dabei gedacht, dass die eine oder andere Funktion jetzt sehr nützlich wäre, die Sie aus Awk, Python, einer anderen Shell oder C kennen? Vielleicht haben Sie auch spezielle Schnittstellen zu Datenbanken wie MySQL oder PostgreSQL oder einer Grafikbibliothek wie GTK+ vermisst? Mit Bashdiff steht Ihnen ohne den Einsatz externer Programme ein Satz neuer Funktionen in den Skripten bereit.
Bei Bashdiff handelt es sich um einen Patch für die Bash 3.0. Einmal gepatcht, definieren Sie die getunte Bash entweder als Standard-Shell oder rufen sie bei Bedarf auf (siehe Kasten “Installation von Bashdiff”). In der Regel genügt der passende Aufruf (“Shebang”) innerhalb des Shellskripts, der dann zum Beispiel #!/usr/local/bin/bash lautet.
Möchten Sie auf die Funktionalität der erweiterten Module zugreifen, wie beispielsweise vplot, so laden Sie diese über den Befehl enable -f /usr/local/lib/william.so Modul im Skript oder Terminal. Um dies zu automatisieren, tragen Sie den Befehl in die Bash-Konfigurationsdatei ~/.bash_profile im Home-Verzeichnis ein. Alle gewünschten Module führen Sie hintereinander auf, durch Leerzeichen voneinander getrennt.
Installation von Bashdiff
Keine der aktuellen Distributionen liefert ein Paket für Bashdiff mit. Somit bleibt nur die Installation über die Quellen. Zunächst benötigen Sie die Bash in der Version 3.0, da Bashdiff ausschließlich mit dieser Version der Bourne-Again-Shell zusammenarbeitet. Aktuelle Distributionen liefern bereits neuere Shell-Versionen (meist Bash 3.2) aus.
Bei Bedarf laden Sie die passende Version als Quellcode-Paket von der Download-Site [1] herunter. Dazu benötigen Sie noch die aktuelle Version von Bashdiff von der Website des Entwicklers William Park [2]. Mittels Patch bauen Sie das “Servicepack” in die Bash ein, um diese anschließend zu kompilieren und im System zu installieren. Stellen Sie zunächst sicher, dass die Programme Patch, Autoconf, Make, Bison (die GNU-Implementation von Yacc), der GNU-C-Compiler GCC samt Abhängigkeiten sowie die Entwicklungspakete von Gtk2 auf Ihrem System bereit stehen. Anschließend gehen Sie vor wie in Listing 1 gezeigt.
Um die so modifizierte Bash als Login-Shell zu nutzen, tragen Sie /usr/local/bin/bash als Shell in /etc/passwd für die gewünschten Benutzer ein. Allerdings bestehen bei OpenSuse Inkompatibilitäten zum Skript /etc/profile.d/complete.bash, das das eingebaute Komplettierungsverfahren der Bash anpasst.
Seit Bashdiff Version 1.18 gehören die erweiterten Module zum Standardpaket. Dennoch gilt es, diese Zusatzmodule separat zu installieren und zu aktivieren. Hierzu gehen Sie wie in Listing 2 beschrieben vor.
# Bash 3.0 herunterladen und entpacken $ cd /usr/local $ wget ftp://ftp.gnu.org/pub/gnu/bash/bash-3.0.tar.gz $ tar -xzf bash-3.0.tar.gz $ ln -s bash-3.0 bash # Patch herunterladen und entpacken $ wget http://home.eol.ca/~parkw/bashdiff/bashdiff-<$$I>Versionsnummer<$$I>.tar.gz $ tar -xzf bashdiff-Versionsnummer.tar.gz # Patchen $ cd bash $ patch -p2 < ../bashdiff-Versionsnummer.diff # Konfigurieren und kompilieren $ autoconf $ ./configure && make -j3 && make install-strip # Testen $ ./bash $ exit
# Erweiterte Module bereitstellen $ cd /usr/local/bash/examples/loadables/william $ make clean && make -j3 && make install $ ldconfig # Folgender Befehl zeigt an, welche Module bereit stehen # Beispiel: Der Eintrag vcat_struct weist auf das Modul vcat $ nm -D ./william.so | grep '_struct' # Beispiel: Laden des Moduls vplot und Anzeigen der Hilfe $ enable -f ./william.so vplot $ help vplot $ help -s vplot
Etwas fürs Auge
Das eben angesprochene Modul vplot druckt bei entsprechenden Parametern eine Grafik aus X- und Y-Werten auf die Standardausgabe, also das Terminal. Listing 3 zeigt ein Skript, das der X-Achse über eine Befehlssubstitution die Reihe der ganzen Zahlen von -100 bis +100 zuweist. Dies erledigt der Befehl seq. Die Wert auf der Y-Achse ergeben sich durch die Multiplikation des X-Wertes mit sich selbst ($((i*i))). Den anzuzeigenden Wertebereich legen die Parameter -x 70 -y 10 über zehn Zeilen automatisch fest. Abbildung 1 zeigt das Ergebnis.
#!/usr/local/bin/bash
enable -f /usr/local/lib/william.so vplot
x=( `seq -100 100` )
y=( `for i in ${x[*]}; do echo $((i*i)); done` )
vplot -x 70 -y 10 x y

vplot zeichnen Sie Graphen in der Konsole. Bashdiff bietet jedoch noch wesentlich komplexere Erweiterungen für Shell-Skripte.” width=”300″ height=”255″ />
Abbildung 1: Mit dem Modulvplot zeichnen Sie Graphen in der Konsole. Bashdiff bietet jedoch noch wesentlich komplexere Erweiterungen für Shell-Skripte.Für den Fall der Fälle
Bashdiff hält einige Erweiterungen für die Fallunterscheidung mittels case bereit. Diese kommt vor allem zum Einsatz, um eine aufwändige If-Abfragen zu vereinfachen. Listing 4 zeigt ein Anwendungsbeispiel: Hierbei sind die Möglichkeiten, die Suchmuster durch Ersetzungszeichen variabel zu gestalten, sehr eingeschränkt. Lediglich ? zum Ersetzen genau eines oder * zum Ersetzen beliebig vieler Zeichen gehören zu den erlaubten Wildcards. Gerade letzteres kommt in diesem Zusammenhang häufig als Auffangstelle für alle nicht konkret definierten Fälle vor. Durch | geben Sie eine Reihe von Zeichenketten an, doch damit erschöpfen sich bereits die Möglichkeiten. Reguläre Ausdrücke (Regular Expressions, kurz: Regex) unterstützt diese Funktion nicht.
case "$monat" in 03|06|09|11) tage=30 ;; # Mar, Jun, Sep, Nov 02) tage=28 ;; # Februar *) tage=31 ;; # alle anderen Monate esac
Das ändert sich mit den Einsatz von Bashdiff. Geben Sie )) statt ) als Abschlusszeichen der gesuchten Zeichenkette an, interpretiert case diese als regulären Ausdruck. Dies funktioniert auch mit mehreren Regex-Ausdrücken, die Sie durch | voneinander getrennt angeben. Durch Angabe von ;;& schließen Sie den Befehlsblock nach einem Treffer ab, doch statt aus der Case-Anweisung heraus zu springen, wird das nächste Muster überprüft.
Zusätzlich erlaubt es dieses Bashdiff-Plugin, einen Then-Else-Block anzuschließen. Im Then-Block legen Sie fest, was passiert, falls die Case-Anweisung einen Treffer produziert. Taucht kein Treffer auf, tritt der Else-Block in Aktion. Er ist optional, wie in der Original-Syntax. Listing 5 zeigt ein einfaches Beispiel, das zum Experimentieren einlädt, und Ihnen so ein Gefühl für die neue Syntax verschafft. Ändern Sie die Werte nach Bedarf, um andere Reaktionen des Skripts zu provozieren.
#!/usr/local/bin/bash a=abc123 case $a in '([a-z]+)([0-9]+)' )) echo "passt" ;;& "abc124" ) echo "passt nicht" ;; esac echo "Geben Sie einen Monat ein" read monat case "$monat" in 'ber$' )) echo "Sep, Okt, Nov oder Dez" ;; 'ar$' )) echo "Jan oder Feb" ;; esac then echo "gueltiger Monat" else echo "ungueltiger Monat" fi
Noch eine Runde mehr?
Bashdiff enthält außerdem Erweiterungen für Schleifenkonstrukte mit for, while und until. Ebenso wie bei case dürfen Sie hier eine Then-Else-Konstruktion an jede Schleife anhängen. Der Then-Anweisungsblock tritt in Aktion, sofern sich die Schleife normal beendet. Dagegen kommt der Else-Block zum Einsatz, wenn Sie die Schleife über den Befehl break abbrechen. Das gilt für alle Schleifentypen, ein Beispiel hierfür zeigt Listing 6.
#!/usr/local/bin/bash
weiter="y"
while [ $weiter == "y" ]
do
echo "Bitte Namen eingeben:"
read name
laenge=${#name}
echo "Der Name ist $laenge Zeichen lang."
echo "Wiederholen? (y|n)"
read weiter
if [ $weiter != "y" ] && [ $weiter != "n" ];then
echo "Weder y noch n!"
break
fi
done then
echo "Schleife sauber verlassen."
else
echo "Kandidat kann nicht tippen."
fi
Für die For-Schleife dürfen Sie zudem jetzt mehrere Laufvariablen nutzen, die die Laufwerte nacheinander annehmen. Damit verarbeiten Sie zum Beispiel Sätze von drei Werten gleichzeitig in der Schleife. Listing 7 zeigt ein einfaches Beispiel dazu. Hierbei kommt ein Standard-Element zum Einsatz: {1..20}. In dieser Weise erzeugen Sie ansteigende (erster Wert kleiner als der zweite) oder absteigende (erster Wert größer als der zweite) Zahlenreihen.
#!/usr/local/bin/bash
for a,b,c, in {1..20}; do
echo $a $b $c
done
Reißverschluss
Im Bashdiff-Funktionsumfang finden sich einige interessante Importe aus Python. Mit arrayzip und arrayunzip fügen Sie Felder zusammen. Vor Gebrauch gilt es, die Module zu aktivieren. Listing 8 enthält ein Beispiel. Nach der Definition der Arrays x und y fügen Sie diese über arrayzip zusammen und geben das neue Konstrukt über den Befehl od aus. Mit od geben Sie Inhalte in bestimmten Formaten aus, wobei der Parameter -c das Escape-Zeichen \0 nach jedem Wert einfügt. Mit arrayunzip dividieren Sie die Felder wieder auseinander, wobei declare -p das Zuweisen der neuen Arrays auf a und b übernimmt.
#!/usr/local/bin/bash enable -f /usr/local/lib/william.so arrayzip arrayunzip x=(1 2 3 4) y=(a b c d) arrayzip x y > xy od -c xy arrayunzip a b < xy declare -p a b
Bash goes Internet
Mit Bashdiff macht die Bash sogar serverseitigen Skriptsprachen wie PHP, JSP und ASP Konkurrenz. Die BASP (Bash Server Pages) ermöglichen es, Bash-Code in HTML-Seiten zu platzieren. Das Beispiel in Listing 9 setzt voraus, dass Sie in einer entsprechenden Shell arbeiten. Im Gegensatz zu den bisherigen Beispielen reicht es nicht, die getunte Bash im Skript aufzurufen. Stattdessen müssen Sie die Bash direkt über /usr/local/bin/bash aufrufen und die notwendigen Module pp_read[3] und basp über enable -f /usr/local/lib/william.so pp_read basp aktivieren. Anschließend starten Sie das Skript durch Eingabe von basp Dateiname im Terminal. Abbildung 2 zeigt das Ergebnis.
<% set – {1..40} %>
<table>
<%
while pp_read a{1..10}; do
echo '<tr>'
printf '<td>%s</td> ' $a{1..10}
echo '</tr>'
done
%>
</table>

Abbildung 2: Mit BASP erstellen Sie bei Bedarf auch eine HTML-Datei mit wenigen Zeilen Shell-Syntax.
Fazit
Die Beispiele vermitteln lediglich einen ersten Eindruck von den Möglichkeiten von Bashdiff. Ein Blick in die sehr knapp gehaltene englischsprachige Dokumentation [3] erleichtert zumindest den Zugang zu allen Funktionen. Neben weiteren nützlichen Features, wie zum Beispiel Schnittstellen zu Datenbanken wie MySQL und PostgreSQL, finden sich in dem Aufsatz auch Möglichkeiten zum Checken einer Kreditkarte, dem Umstellen auf koreanischen Sprache sowie dem Konvertieren von Audiodateien in iPod-Formate.
Bei all diesen interessanten Funktionen hat Bashdiff jedoch den Nachteil, dass es ausschließlich im Zusammenspiel mit Bash-Version 3.0 läuft – die findet sich nicht auf jedem System. Wer seine Skripte auf andere Rechner kopiert, dem steht auf dem Zielsystem so mitunter nicht nur die Installation von Bashdiff bevor, sondern zusätzlich das Kompilieren einer neuen Shell.
Das teilweise umständliche Aktivieren verschiedener Funktionen sowie von Bashdiff selbst verhindert derzeit eine größere Verbreitung. Dennoch bleibt der Eindruck, dass gerade Entwickler, die unter verschiedenen Sprachen (C, Python, Awk) arbeiten, mit Bashdiff einige nützliche Funktionen wiederfinden, die ihnen die Arbeit mit Shellskripten erleichtern.
Glossar
-
Wildcards
-
Platzhalter für Zeichen oder Zeichenketten.
[1] Bash: ftp://ftp.gnu.org/pub/gnu/bash
[2] Bashdiff: http://home.eol.ca/~parkw/bashdiff
[3] Dokumentation zu Bashdiff (engl.): http://home.eol.ca/~parkw/index.html#bashdiff





