Es ist Zeit für Basht Practices

Fehlendes Qualitätsmanagement bei Shell-Skripten stellt ein Risiko da. Mit wenigen Schritten kriegen Sie das Problem in den Griff und die Skripte Ihres Teams auf das nächste Level. 

Dr. Michael Köpf
3. November 2020

Keiner redet gerne darüber, doch jeder nutzt sie. Sie verstecken sich in Kubernetes-CronJobs, in den Job-Definitionen einer CI/CD-Pipeline oder im Dockerfile: Shell-Skripte!

Ob man Bash, Dash und Konsorten nun als ernstzunehmende Programmiersprachen ansieht oder nicht – faktisch finden sie sich in allen größeren Infrastruktur- und Software-Projekten, und zwar nicht selten an kritischer Stelle. Auch im Zeitalter der Cloud haben sie nicht an Bedeutung verloren. Im Gegenteil: Den Sprung in die moderne Welt von Docker, Kubernetes, Microservices und Serverless Computing haben Shell-Skripte besser überstanden als manche High-Level-Sprache aus der späten Desktop-Ära.

Mit der Frage, ob diese Tatsache nun erfreulich ist oder nicht, möchte ich mich hier gar nicht aufhalten. So oder so kann man Stand 2020 getrost davon ausgehen, dass uns Shell-Skripte noch sehr, sehr lange begleiten werden. Denn ähnlich wie das altehrwürdige C über Jahrzehnte bis heute relevant geblieben ist, während andere Sprachen kamen und gingen, so hält sich auch die Shell-Sprachfamilie rund um Bash hartnäckig, obwohl es zum Beispiel mit Python oder Ruby durchaus ernstzunehmende Konkurrenz im Scripting-Bereich gäbe. 

Populär sind und waren Shell-Skripte dennoch nie. Fragt man ein Dev-Team nach seinem Language-Stack, so werden Bash & Co. meist „vergessen“, obwohl sie zum Teil an entscheidender Stelle wirken. Frei nach dem Motto: „Eigentlich haben wir hier gar keine Shell-Skripte“. Die Bash zu bashen ist vielerorts ein populärer Zeitvertreib.

Klar, denn besonders glamourös geht es nicht zu, in der Shell. Hier geht es nicht um Monaden, algebraische Datentypen oder andere intellektuell besonders ästhetische Konzepte. Nein, es geht – ganz unprätentiös – einfach nur darum Arbeit wegzuschaffen.

Und weil ihnen dieser Nimbus der Drecksarbeit anhaftet, werden Shell-Skripte oft anscheindend nur geschrieben, wenn es wirklich gar nicht mehr anders geht. Dann verbringt eine arme Entwicklerin einen ganz üblen Nachmittag damit, ein Skript zusammen zu schustern. Irgendwie. Bis es läuft. Und dann wird der Editor schnellstmöglich geschlossen, das Skript nie wieder angefasst und versucht, in Zukunft möglichst wenig daran zu denken. Linting? Code Analysis? Automatisierte Tests? Fehlanzeige!

Da lacht das Developer-Herz: Ein Shell-Skripte möchte debuggt werden.

Dabei gibt es keinen Grund, bei Shell-Skripten alle Best Practices links liegen zu lassen, die in mühsamer Arbeit im restlichen Entwicklungsprozess etabliert wurden. Gerade wer in seinem Team ernsthaft DevOps etablieren möchte, kommt nicht daran vorbei, solide Shell-Kompetenz im Team zu verankern.

Wie also dabei vorgehen? Ich empfehle folgenden 5-Punkte-Plan zum Einstieg.

1. Die Akzeptanzphase, oder: „Ja, ich nutze Bash.“

Gestehen Sie sich ein, dass es in Ihrem Projekt Shell-Skripte gibt. Das ist nicht schlimm. Es geht fast allen so.
Machen Sie Ihren Frieden damit.

2. Machen Sie Shell-Skripte zu First-Order-Citizens Ihrer Code-Basis

Jetzt, wo wir unser Dasein als Shell-Skripter akzeptiert haben, gibt es keinen Grund mehr, unsere Skripte in dunklen Kellern zu verstecken. Viel zu oft musste ich schon mitansehen, wie entscheidende Skripte zum Aufsetzen ganzer Umgebungen auf dem Laptop eines Entwicklers lokal gespeichert waren. Die Endung .sh gehört aber nicht ins .gitignore-File! Shell-Skripte gehören ebenso unter Versionskontrolle gestellt wie jeglicher Hochsprachen-Code.

In vielen Projektteams beobachte ich zudem die Tendenz, Shell-Skripte als Pet-Projekte einzelner Entwickler zu behandeln. Dann sind Sätze zu hören wie „Der Batch-Datenimport? Da hat die Miriam irgendwo ein Skript für.“ Wie in der restlichen Codebasis muss die Ownership an den Skripten aber immer beim gesamten Team liegen.
Gearbeitet wird also auch an ihnen mit Pair Programming, Code-Review und Pull-Requests.

3. Testen Sie Ihre Shell-Skripte automatisiert

Selbst in Teams, die sich dem Test-Driven-Development verschrieben haben, bleiben Shell-Skripte meist außen vor. Angesichts der schon angesprochenen kritischen Rolle dieser Skripte und dem damit verbundenen Risiko ist das nicht nur unnötig sondern schlicht fahrlässig. Wie über jedem Stück Code sollte man über Shell-Skripten eine stabile Testpyramide errichten. Nicht nur klassische Unit-Tests, sondern vorallem auch Integrationstests sollten dabei nicht zu kurz kommen. Schließlich werden Shell-Skripte in der Regel gerade dort eingesetzt, wo viele, sehr verschiedenartige System miteinander verkabelt werden müssen.

Mit BATS, ShellSpec, shUnit2 und bach stehen mittlerweile eine ganze Reihe von Frameworks für automatisierte Tests Ihrer Shell-Skripte zur Verfügung.

4. Committen Sie sich auf Skript-Qualität und verankern Sie diese programmatisch

Es ist so einfach, ein schlechtes Skript zu schreiben, und so schwierig, gute Qualität zu etablieren, vorallem, wenn das Team in Sachen Shell-Kompetenz sehr heterogen aufgestellt ist. Stack-Overflow ist voll mit Fragen wie „What is the difference between “…”, ‚…‘, $’…‘, and $“…” quotes?“ oder „What is the difference between $* and $@“, weil solche „Details“ in Shell-Skripten essenziell sind.

Viele Pitfalls lassen sich aber programmatisch abfangen, um sie dann gezielt auszumerzen. Dafür sorgen Tools wie ShellCheck, die statische Analyse und Linting von Shell-Skripten bieten.

Das folgende Skript, script0.sh, mag ShellCheck z.B. nicht.

#!/bin/bash
echo "$myvar"

Und `shellcheck script0.sh` liefert

In script0.sh line 2:
  printf "%s\n" $SOMEVAR
                ^------^ SC2086: Double quote to prevent globbing and word splitting.

Did you mean: printf "%s\n" "$SOMEVAR"
For more information: https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...

Netter Nebeneffekt: Jeder Hinweis von ShellCheck ist eine Lektion für’s Leben. Quasi nebenbei bekommt man so viele Best-Practices eingetrichtert und steigert Schritt für Schritt die eigene Shell-Kompetenz. Ist man dann erstmal auf den Geschmack gekommen, empfehlen sich systematischere Quellen, z.B. der Klassiker Pro Bash Programming oder aber auch andere wunderbare Bücher.

Eine gute Nachricht für diejenigen, die bereits einen Code-Quality-Prozess mit entsprechendem Tooling auf Basis von SonarQube etabliert haben: ShellCheck lässt sich hier per Plugin direkt integrieren.

5. Continuous Integration für Shell-Skripte

Hat man automatisierte Tests und Qualitätschecks erstmal etabliert, ist es ein kleiner Schritt, diese auch in die CI-Pipeline zu heben.

Mit dem oben genannten 5-Punkte-Plan wird das Niveau der Shell-Skripte in Ihrem Team nachhaltig gesteigert. Nach meiner Erfahrung kann dadurch bereits manches heiße Wochenende vor oder nach einem Releasetermin vermieden werden.

Über den Autor

Dr. Michael Köpf
Geschäftsführer

Als KI-Experte und zertifizierter Software-Architekt verantwortet Michael Köpf unsere technische Expertise und überbrückt für Sie das Gap zwischen Wissenschaft und Praxis.