Open Source im professionellen Einsatz
Linux-Magazin 02/2010

Shellskripte aus der Stümper-Liga - Folge 5: Cat, Sed, Grep & Co. vermeiden

Bash Bashing

Es gibt kaum ein Bash-Skript, das ohne Standard-Unix-Tools auskommt. Allerdings ist die Shell inzwischen so mächtig, dass viele verzichtbar sind.

660

Wenn Fotofreunde ein Motiv mit mehreren Belichtungseinstellungen fotografieren, ergeben sich mit der richtigen Software erstaunliche Resultate: High Dynamic Range nennen das die Profis [1]. Mühsam nur, wenn es viele Bilder auf einmal zu konvertieren gibt. Linux-Anwender schreiben sich für solche wiederkehrenden Aufgaben ein Skript. Listing 1 zeigt einen Ausschnitt aus einem solchen Skript, das aus Raw-Dateien automatisch HDR-Dateien erzeugt [2].

Listing 1: Zu viele externe
Befehle in »createHDR.sh«

01 i=0
02 cat "$DIR"/pfs.hdrgen | while read LINE; do
03   echo "${FILES[$i]} $LINE" | cut -d' ' -f1,3- >> "$DIR"/pfs_updated.hdrgen
04   let "i = $i +1"
05 done

Der Code im Beispiel ist nicht falsch, aber kompliziert und unverständlich. Auch wenn das Beispiel extrem anmutet: Man kommt nicht immer an per Pipe verbundenen Befehlsketten vorbei. Doch oft sind solche Konstrukte überflüssig und zeugen nur von mangelnder Kenntnis der Bash-Möglichkeiten. Diese Folge des Bash Bashing zeigt ein paar Wege auf, ohne externe Befehle auszukommen.

Eine Basis finden

Ein bekannter Klassiker in Skripten ist die Zuweisung »verz=$(dirname "$0"), um das Verzeichnis zu finden, in dem das Skript liegt. Dabei geht das auch einfacher mit »verz="${0%/*}"«. Geht es um den reinen Programmnamen, hilft »prog="${0##*/}"« statt des externen Aufrufs:

prog=`basename "$0"`

Das Syntaxelement in beiden Fällen heißt Parameter-Expansion. Der Wert einer Variablen - hier des nullten Positionsparameters - übernimmt die Bash dabei nicht einfach, wie er ist, sondern verändert ihn zusätzlich. Das Prozentzeichen löscht dabei den auf sich selbst folgenden Text von hinten, die Raute von vorne. Bei doppeltem Prozentzeichen oder Raute verfährt die Bash gierig und löscht den maximal möglichen String, der passt. In der einfachen Form bleibt die Bash konservativ und nimmt nur den ersten passenden Ausdruck.

Der Trick ohne externes Programm »dirname« klappt allerdings nicht immer, denn die Shellvariante gibt einen Punkt zurück, wenn ihr Argument beispielsweise »demo.sh« lautet, die Bash hingegen den kompletten Namen übrig lässt. Die Tabelle 1 gibt einen Überblick verschiedener Optionen und Funktionen der Parameter-Expansion.

Tabelle 1:
Parameterexpansion

 

Zeichen

Bedeutung

Erklärung

#

Einfaches Löschen von vorne

»x="aabc"«: das führende »a«
entfernt »${x#a}«

##

Gieriges Löschen von vorne

»x="aabc"«: alle führenden »a«
entfernt »${x##a}«

%

Löschen von hinten

»x="abcc"«: das letzte »c« entfernt
»${x%c}«

%%

Gieriges Löschen von hinten

»x="abcc"«: alle »c« von hinten
entfernt »${x%%c}«

/

Ändern eines Textes (erstes Vorkommen)

»x="abcabc"«: »${x/b/x}« erzeugt
»axcabc«

//

Ändern eines Textes (alle Vorkommen)

»x="abcabc"«: »${x//b/x}« erzeugt
»axcaxc«

^

Erstes Zeichen in Großbuchstaben umwandeln (Bash 4)

»x="abcabc"« verwandelt »${x^a}« in
»Abcabc«; »${x^}« wandelt einen beliebigen
ersten Buchstaben um

^^

Alle Zeichen in Großbuchstaben umwandeln (Bash 4)

»x="abcabc"« verwandelt »${x^^b}« in
»aBcaBc«; »${x^^}« wandelt den kompletten
String um

,

Erstes Zeichen in Kleinbuchstaben umwandeln (Bash 4)

»x="ABCABC"« verwandelt »${x,A}« in
»aBCABC«; »${x,}« wandelt einen beliebigen
ersten Buchstaben um

,,

Alle Zeichen in Kleinbuchstaben umwandeln (Bash 4)

»x="ABCABC"« verwandelt »${x,,B}« in
»AbCAbC«; »${x,,}« wandelt den kompletten
String um

Auf Echo verzichten

Will der Programmierer den Inhalt von Shellvariablen an Programme verfüttern, dann scheint der Echo-Befehl ein probates Mittel:

zeilen=`echo $foo | grep -i muster`
if [ -n "$zeilen" ]; then
  ...
fi

In manchen Shells ist dieses Konstrukt tatsächlich notwendig. Die Bash dagegen erlaubt es, den Inhalt von Shellvariablen direkt an die Standardeingabe eines Programms zu binden:

zeilen=`grep -i muster <<< "$foo"`
if [ -n "$zeilen" ]; then
  ...
fi

Alternativ darf das Kommando auch direkt hinter dem Schlüsselwort »if« stehen, denn dort sind auch andere Befehle außer »test« oder seines häufiger benutzen Alias »[« erlaubt:

if grep -qi muster <<< "$foo"; then
  ...
fi

Die Bedingung ist in diesem Fall abhängig vom Returncode des Kommandos, das die Shell auch in »$?« ablegt.

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Bash Bashing

    Über Klicki-Bunti und grafische Oberflächen sollten Kommandozeilen-Fans gerechterweise nur dann die Nase rümpfen, wenn sie die Effizienz steigernden Bedienungstricks der interaktiven Shell auch wirklich kennen und benutzen. Diesmal: Bash Completion.

  • Bash Bashing

    Zu viele Dateien, zu viele Verzeichnisse: Wer gezielt nach Daten sucht und wiederholbare Arbeiten plant, schreibt ein Skript. Doch Obacht: Fallen lauern.

  • Aufpoliert

    Die Bash begleitet Linux seit seinen Kindertagen. Trotz ihres biblischen Alters und ihres hohen Reifegrads feilen die Entwickler immer noch an der Shell. Kürzlich veröffentlichten sie Version 4.0. Das Linux-Magazin schaut sich an, ob ein Umstieg lohnt.

  • Bash Bashing

    Die Fehlersuche in Skripten erscheint um vieles bodenständiger als in kompilierten Programmen. Jenseits der "bash -x"- Hausmannskost hält die Bash aber einige Überraschungen auf der Debugging-Karte bereit.

  • Bash Bashing

    Völker hört die Signale: Internationalisierung ist für Desktop-Programme üblich, bei von Menschen bedienten Skripten nicht. Dabei erfordert die Völkerverständigung nur wenig Mehrarbeit.

comments powered by Disqus

Stellenmarkt

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.