Open Source im professionellen Einsatz

Shellskripte aus der Stümper-Liga - Folge 9: Viel finden

Bash Bashing

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

Manche Muster kommen in Programmen immer wieder vor. Manche Fehler von Programmierern finden aufmerksame Code-Studierer ebenfalls regelmäßig. Solche Anpassungen von Code und das Verbessern von oft wiederholten Unregelmäßigkeiten rufen nach einem Skript, das die lästige Aufgabe übernimmt. Dazu liefert beispielsweise die norwegische PHP-Schmiede EZ Systems in ihrem Paket "EZ Components" ihres Content-Management-Systems ein Bash-Skript mit [1], das einen PHP-Verzeichnisbaum durchsucht und eine Reihe automatischer Änderungen der Syntax vornimmt, um Coderichtlinien einzuhalten (siehe Listing 1).

Listing 1:
»syntax-check.sh«

01 #!/bin/sh
02 for i in `find . -name *.php`; do
03     php -l $i | grep -v "No syntax errors"
04 done
05 
06 for i in `find . -name *.php`; do
07     cat $i | 
08     sed -e 's/[[:space:]]while(/ while (/' | 
09     sed -e 's/[[:space:]]if(/ if (/' | 
10     sed -e 's/[[:space:]]else(/ else (/' | 
11     sed -e 's/[[:space:]]elseif(/ elseif (/' | 
12     sed -e 's/[[:space:]]catch(/ catch (/' | 
13     sed -e 's/[[:space:]]foreach(/ foreach (/' | 
14     sed -e 's/[[:space:]]switch(/ switch (/' 
15                    > /tmp/temporary.php
16   cp /tmp/temporary.php $i
17 done
18 
19 echo "Checking for boolean/integer"
20 
21 for i in `find . -name *.php | grep trunk/src`; do
22     cat $i | sed -e 's/@param boolean/@param bool/'> /tmp/temporary.php; cp /tmp/temporary.php $i; done
23 for i in `find . -name *.php | grep trunk/src`; do
24     cat $i | sed -e 's/@param integer/@param int/'> /tmp/temporary.php; cp /tmp/temporary.php $i; done
25 [...]
26 
27 echo "Checking wrong braces placement for functions"
28 
29 grep -rn "function" * | grep "{" | grep -v "{@" | grep -v svn | grep ".php:"
30 grep -rn "class" * | grep "{" | grep -v "{@" | grep -v svn | grep ".php:"
31 grep -rn "interface" * | grep "{" | grep -v "{@" | grep -v svn | grep ".php:"
32 
33 echo "Checking for wrong if/else + brackets"
34 
35 grep -rn "if" * | grep "{" | grep -v svn | grep ".php:"
36 grep -rn "else" * | grep "{" | grep -v svn | grep ".php:"
37 
38 echo "Checking for wrong 'try' syntax':"
39 
40 grep -nr "try" * | grep "[}{]" | grep -v svn-base | grep ".php"
41 
42 echo "Checking for wrong closing bracket:"
43 
44 grep -nr "[^[:space:](]);" * | grep -v svn-base | grep -v tests | grep ".php"
45 
46 echo "Checking for wrong opening bracket:"
47 
48 grep -nr "([^[:space:]C)]" * | grep -v svn-base | grep -v tests | grep -v "(string)" | grep -v "(int)" | grep -v "(float)" | grep -v "*" | grep ".php:"
49 [...]

Best of Bashing

Das Skript ist insofern ein Klassiker, als dass es alle Wesenszüge eines typischen Tools im Praxiseinsatz trägt: Es funktioniert auf dem aktuellen Datenbestand, es ist über Jahre gewachsen und es macht Fehler hinsichtlich Robustheit und Performance. Wer die tatsächliche, inhaltliche Intention des Helfer-Werkzeugs beiseite lässt,die die EZ-Entwickler ohnehin weitgehend mittels in das Skript mit eingebettetem PHP verfasst haben, findet viele Verbesserungsmöglichkeiten, die vergangene Bash Bashings thematisiert haben: So nutzt etwa das Skript bereits in Zeile 2 die nicht schachtelbaren und mit vielfältigen Quoting-Problemen behafteten Backquotes, die moderne Basher besser mit »$(Kommando)« notieren [2].

Ebenfalls regelmäßig gehen Tools dann baden, wenn sie Dateien mit Leerzeichen bearbeiten sollen. Weil die Entwickler des Syntax-Checkers die Variablenauswertung weder in Zeile 3 noch sonst irgendwo im kompletten Skript schützen, scheitert das Programm an Dateien wie »habe leerzeichen.php« - vielleicht ungewöhnlich, aber denkbar und allemal erlaubt. Robustheit heißt schließlich, auch in ungewöhnlichen Situationen noch korrekt zu reagieren [3].

Massig unnötige Befehle

Zeile 7 leitet mit einem unnötigen Aufruf von »cat«, der sich auch »< "$i"« notieren ließe [4], einen Reigen von vielen »sed«-Prozessen ein. Auch wenn Entwickler die einzelnen Aufrufe mit etwas Aufwand sogar ebenfalls innerhalb der Bash realisieren könnten [5], ist es nicht jedermanns Sache, die sehr spezielle Syntax zu lernen. In jedem Fall reicht aber ein einzelner Aufruf innerhalb der Schleife. Im Trunk-Verzeichnis der EZ-Components finden sich allein über 3 600 PHP-Dateien, jede einzelne aktiviert zwischen Zeile 6 und 17 daraufhin neun eigene Prozesse, nämlich einmal »cat«, siebenmal »sed« und ein problematisches »cp«. Das sind weit über 30 000 Prozesse nur für diesen Abschnitt. Ein halbes Dutzend Variationen von diesem Programmmuster finden sich in den kommenden Zeilen.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 2 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook