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
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



