Tue, 07 Jul 2020 00:00:00 +0200
bash, programmieren, script, shell, software

Shellcheck

Ein Shell-Skript ist schnell geschrieben. Ich rufe ein paar Befehle auf, liste die History, kopiere die Befehle, die funktioniert haben, steuere den Ablauf mit if ... then ... fi, case ... esac oder Schleifen. Schon ist das Skript fertig und wartet darauf, mir beim nächsten Mal Arbeit abzunehmen.

So weit, so gut. Aber dann ändert sich die Umgebung, die Aufrufparameter oder da ist eine Datei mit Leerzeichen im Dateinamen und schon macht das Skript etwas anderes, als es machen sollte.

Sicher, es gibt dicke Bücher über Shell-Programmierung und es gibt Style-Guides, die helfen, die gröbsten Klippen zu umschiffen, so dass das Skript nicht an simplen Dingen scheitert. Aber Hand aufs Herz, wer hat das alles im Kopf? Ich nicht.

Muss ich auch nicht, denn es gibt Programme wie Shellcheck, die mein Skript begutachten und mich auf subtile Fehler hinweisen. Das Gute daran: zu jeder Warnung gibt es eine Erklärung, was das Problem an dieser Stelle sein könnte, und Ratschläge, wie ich damit umgehen kann.

Dazu kann ich es online verwenden oder auf meinem Rechner installieren. Einige Editoren können mit Shellcheck schon beim Schreiben des Skripts Vorschläge machen. Build- oder Test-Systeme können die Qualität des Skripts überwachen.

Zum Beispiel erzeugt dieses Stück Code

#!/bin/sh
## Example: a typical script with several problems
for f in $(ls *.m3u)
do
  grep -qi hq.*mp3 $f \
    && echo -e 'Playlist $f contains a HQ file in mp3 format'
done

diese Meldungen:

Line 3:
for f in $(ls *.m3u)
         ^-- SC2045: Iterating over ls output is fragile. Use globs.
              ^-- SC2035: Use ./*glob* or -- *glob* so names with dashes won't become options.

Line 5:
  grep -qi hq.*mp3 $f \
           ^-- SC2062: Quote the grep pattern so the shell won't interpret it.
                   ^-- SC2086: Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
  grep -qi hq.*mp3 "$f" \

Line 6:
    && echo -e 'Playlist $f contains a HQ file in mp3 format'
            ^-- SC2039: In POSIX sh, echo flags are undefined.
               ^-- SC2016: Expressions don't expand in single quotes, use double quotes for that.

Gut, damit weiß ich die problematischen Stellen und ungefähr, was ich machen soll, aber noch nicht genau, warum.

Hier hilft das Shellcheck-Wiki, das die Beschreibungen der Warnungen und Vorschläge in ausführlicher Form enthält. Habe ich das Skript bei shellcheck.net online überprüft, bekomme ich direkt in der Shellcheck-Ausgabe Links zu den betreffenden Seiten.

Normalerweise erkennt Shellcheck am Shebang (#!) in der ersten Zeile, für welche Shell - bash, ksh oder sh - ein Skript geschrieben ist und berücksichtigt automatisch deren Eigenheiten.

Manchmal fehlt jedoch diese Angabe in der ersten Zeile oder das Skript ist für eine andere Shell, als oben ausgewiesen (das Install-Skript von GNU-Guix zum Beispiel). Dann kann ich mit der Option -s vorgeben, welche Shell gemeint ist.

Je nach Ergebnis der Untersuchungen gibt Shellcheck entsprechende Rückgabewerte. Damit kann ich es in einen Build-Prozess einbinden und so eine automatische Qualitätskontrolle etablieren.

So gibt es für mich keine Ausreden mehr für schlechte Shell-Skripte. Shellcheck macht mich auf problematische Stellen aufmerksam und ich kann dabei noch etwas lernen. Darum verwende ich es für alle neuen Skripts und für die alten, die ich nochmal anfassen muss.