Skip to content

Bessere Shell-Skripte

Shell-Skripte sind gegenüber anderen Programmiersprachen natürlich nicht das "Non-plus-ultra", aber sie sind für Ablaufsteuerungen - dafür sind sie gemacht - eine gute Wahl. Für alles, was grösser ist, empfehle ich eine "richtige Programmiersprache". Ich bin als Systemadministrator ein grosser Fan von Python und - schon länger nicht mehr genutzt - Perl, aber auch Sprachen wie Raku, Ruby oder irgendetwas mit Compiler sind natürlich gute Alternativen.

Ich beziehe mich im Folgenden auf die Bash, weil das die Shell ist, die ich täglich auf verschiedenen Systemen und Architekturen benutze.

Tipp 1:

Schreibt in den Shebang #! zu Beginn des Skriptes genau die Skriptsprache mit der Ihr auch getestet habt und nicht - weil alle das machen - /bin/sh. Auf Debian basierten Systemen ist /bin/sh ein Link auf dash, bei Alpine ist es ein Link auf Busybox, auf Red Hat basierten Systemen ein Link auf bash.

An dieser Stelle möchte ich gerne noch auf diesen alten Artikel hinweisen.

Tipp 2:

Skripte laufen auch im Falle eines Fehlers weiter. Ich halte das für ein blödes Verhalten, was sehr häufig zu Fehlern führt. Glücklicherweise kann man das Verhalten abstellen.

Entweder man ruft die Shell mit -e auf, setzt den Shebang entsprechend oder schreibt set -e an den Anfang des Skriptes oder vor die Zeilen für die das Setting gelten soll. Mit set +e kann man wieder das alte Verhalten herstellen.

Meine Empfehlung ist, die Langform set -o errexit zu verwenden, das ist deutlich lesbarer. (Altes Verhalten kann man mit set +o errexit wieder herstellen).

Shellzeilen gelten als fehlerhaft, wenn der exit-Code des letzten Kommandos der Zeile ungleich 0 (null) ist. Das bedeutet unter anderem, dass man den Exitcode einer einzelnen Zeile durch Hinzufügen von || true auf "nicht fehlerhaft" ändern kann.

Tipp 3:

Wie im letzten Tipp beschrieben, ist das letzte ausgeführte Kommando einer Zeile ausschlaggebend dafür, ob eine Zeile mit oder ohne Fehlercode beendet wird.

Der Eintrag set -o pipefail sorgt dafür, dass eine Zeile als fehlerhaft "gesehen" wird, wenn auch nur ein Kommando der über Pipes vernetzten Kommandos einer Zeile fehlschlägt.

Tipp 4:

Nicht gesetzte oder "leere" Variablen sind häufig ein Problem.

Um eine nicht gesetzte Variable mit einem Fehler zu quittieren, kann man das Kommando set -o nounset oder set -u verwenden.

Tipp 5:

Es ist generell eine gute Idee, alle Variablen mit doppelten Anführungszeichen zu umgeben, ganz besonders dann, wenn es um Dateien geht. Auch, wenn man selber keine Dateien mit Leerzeichen (oder anderen "Internal Field Separators" (IFS)) erstellt, heisst es nicht, dass man nicht auf solche treffen kann.

Nachtrag:

Christoph hat in diesem Kommentar zur recht darauf hingewiesen, dass es besser ist /usr/bin/env bash zu verwenden, das benutzt die erste Bash, die der Benutzer im Pfad hat und funktioniert auch auf Systemen, auf denen die Bash in einem anderem Pfad liegt als /bin/bash.

Zusammenfassung:

Meine Erfahrung ist, dass man mit den fünf Tipps rund 80% aller Probleme mit Shellskripten umschifft bzw. Skripte mit Fehlern rechtzeitig abbricht.

#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail

# Und Variablen immer mit doppelten Anführungszeichen verwenden.

echo "${Variable}"

Es gibt noch viele weitere Tipps, aber das sind meiner Ansicht nach die wichtigsten.

Trackbacks

Dirks Logbuch am : Bessere Shell-Skripte

Vorschau anzeigen
Shell-Skripte sind gegenüber anderen Programmiersprachen natürlich nicht das "Non-plus-ultra", aber sie sind für Ablaufsteuerungen - dafür sind sie gemacht - eine gute Wahl. Für alles, was grösser ist, empfehle ich eine "richtige Programmiersprache". Ich

Dirks Logbuch am : Linkdump 52/2021

Vorschau anzeigen
Jetzt ist er da, der letzte Linkdump 2021. Ich hatte zwar ausreichend Artikel, aber die meisten waren so alt, dass sie nicht mehr auf ihren Webseiten verfügbar waren. Daher bekommt Ihr jetzt einen aktuellen Artikel, den ich sehr gut finde und eine kleine

Kommentare

Ansicht der Kommentare: Linear | Verschachtelt

Christoph Stoettner am :

*Super danke für die Zusammenfassung. Als Ergänzung, es gibt die Möglichkeit die Shebang über
CODE:
!#/usr/bin/env bash

zu benutzen, das hat mir in Zusammenhang mit Dash/Bash etc weit weniger Probleme bereitet. S.a. https://www.cyberciti.biz/tips/finding-bash-perl-python-portably-using-env.html

Dirk Deimeke am :

*Vielen Dank Christoph, das ist ein sehr guter Hinweis.

Ich ergänze das mal im Artikel.

tux. am :

*Ich bin als Systemadministrator ein großer Gegner von Python (Abhängigkeitshölle). So kann’s gehen.

Dirk Deimeke am :

*Kommt darauf an, welche Module Du benutzt (bei uns nur Core), aber ja, ich sehe Dein Problem.

Das hast Du aber auch mit Shellskripten.

tux. am :

*Echt? Welche Shellskripte hören wegen fehlender Abhängigkeiten beim nächsten Systemupdate plötzlich auf zu funktionieren?

Dirk Deimeke am :

*Skripte, die externe Kommandos nutzen - beispielsweise in einer Pipe - sind ebenfalls von den Versionen der externen Programme abhängig.

Das Problem habe ich nicht auf Enterprise-Linux-Distributionen. Gut, da habe ich das auch nicht mit Python.

Christoph Petrausch am :

*Die Abhängigkeiten hat man bei Shell-Skripten auch. IMHO viel schlimmer als bei Python, denn ich kann in Shell-Skripten keine benötigen Versionen über ein dependency Tool angeben. Das mag innerhalb desselben OS kein Problem sein, aber sobald du ein Shell Skripte schreiben musst was auf Ubuntu/Debian/Redhat funktionieren soll, hast du ein Problem. Klar, kannst du dich auf POSIX zurückziehen. Dann hast du aber viele CLI Toolweiterentwicklung der letzten 20 Jahre ausgeklammert.

Fryboyter am :

*Wer seine Shellscripte testen will, kann sich auch https://github.com/koalaman/shellcheck ansehen. Neben den bereits genannten Tipps werden oft noch weitere Verbesserungsvorschläge angezeigt.

tux. am :

*ShellCheck kommt mit POSIX nicht klar: "Use $(...) notation instead of legacy backticks `...`" - geht halt nicht in einer klassischen POSIX-Shell.

Dirk Deimeke am :

*Hier bei mir geht es auch explizit um die Bash.

Den Leuten bei ShellCheck sollte man mal sagen, dass sie sh explizit ausklammern müssen.

Dirk Deimeke am :

*Das halte ich für ein gutes Tool, viele Vorschläge sind aber auch akademisch oder rein kosmetischer Natur.

Christoph Petrausch am :

*Wir haben mit Shellcheck nur positive Erfahrungen gemacht. Wir schreiben aber auch wenn nur bash und da echt kurze Skripte. Paar Checks haben wir deaktiviert. Aber alleine der Fakt, dass Skripte danach konsistent aussehen und funktionieren ist Gold wert. Insbesondere in einer Umgebung in der eher bash Noobs unterwegs sind. Generell ist das für mich eine der unterschätzten Eigenschaften einer Codebase. Einige Dinge sind einfach Geschmackssache. Da ist es dann als Team/Organisation wichtig konsistent zu sein. Und da helfen dann Linter wie shellsheck enorm.

Dirk Deimeke am :

*Das kann ich super gut nachvollziehen.

Ich kenne einige Unternehmen, die einen verbindlichen Styleguide für jede Programmiersprache einsetzen und wenn ich mich richtig erinnere, sind die von Google sogar öffentlich.

Gefunden: Shell Style Guide

Bruno am :

*Kam gerade durch meine Mastodon Timeline. Passt so schön zu diesem wunderbaren Artikel. :-)

https://octodon.social/@eptf/105080666953522366

Dirk Deimeke am :

*Huch, danke. Spannend, wir haben nicht voneinander abgeschrieben (vermute ich).

Kommentar schreiben

Gravatar, Favatar, Pavatar, Identica, Twitter, MyBlogLog Autoren-Bilder werden unterstützt.
BBCode-Formatierung erlaubt
Umschließende Sterne heben ein Wort hervor (*wort*), per _wort_ kann ein Wort unterstrichen werden.
Standard-Text Smilies wie :-) und ;-) werden zu Bildern konvertiert.
Die angegebene E-Mail-Adresse wird nicht dargestellt, sondern nur für eventuelle Benachrichtigungen verwendet.
:'(  :-)  :-|  :-O  :-(  8-)  :-D  :-P  ;-) 
Formular-Optionen