Ein fehlendes Anführungszeichen in einem Admin-Skript ist ungefähr so lustig wie `rm -rf "$BACKUP_DIR/"*`, wenn `$BACKUP_DIR` leer ist. Also: gar nicht. Genau deshalb haben wir ShellCheck in die CI geworfen. Nicht als Deko, sondern als Türsteher für unsere Shell-Skripte.
ShellCheck ist ein statischer Analyzer für Shell-Skripte. Das Tool schaut sich Bash, sh, dash und ksh an und meckert bei typischen Fehlern: unquotierte Variablen, kaputte Tests, falsche Redirects, unsichere Globs, tote Variablen. Kurz: Dinge, die nachts um 03:17 Uhr Tickets erzeugen.
Installation lokal ist unspektakulär:
```bash
apt install shellcheck
```
Oder auf macOS:
```bash
brew install shellcheck
```
Dann ein Skript prüfen:
```bash
shellcheck backup.sh
```
Klassiker:
```bash
!/bin/bash
for file in $BACKUP_DIR/*.tar.gz; do
scp $file root@$HOST:/backup/
done
```
ShellCheck schreit hier völlig zurecht. `$BACKUP_DIR`, `$file` und `$HOST` sind nicht gequotet. Wenn Pfade Leerzeichen enthalten oder Variablen leer sind, wird’s spannend. Die bessere Variante:
```bash
!/usr/bin/env bash
set -euo pipefail
for file in "$BACKUP_DIR"/*.tar.gz; do
scp "$file" "root@$HOST:/backup/"
done
```
`set -euo pipefail` ist kein magischer Schutzschild, aber ein brauchbarer Helm. `-e` beendet bei Fehlern, `-u` bei nicht gesetzten Variablen, `pipefail` sorgt dafür, dass Pipelines nicht alles schönreden.
Damit das nicht nur auf dem Laptop des gewissenhaften Admins läuft, kommt ShellCheck in die CI. Beispiel GitLab CI:
```yaml
stages:
- lint
shellcheck:
image: koalaman/shellcheck-alpine:stable
stage: lint
script:
- shellcheck scripts/*.sh
```
Wenn deine Skripte in mehreren Verzeichnissen liegen:
```yaml
script:
- find . -type f -name "*.sh" -print0 | xargs -0 shellcheck
```
Für GitHub Actions sieht das so aus:
```yaml
name: shellcheck
on:
push:
pull_request:
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ShellCheck
run: sudo apt-get update && sudo apt-get install -y shellcheck
- name: Run ShellCheck
run: find . -type f -name "*.sh" -print0 | xargs -0 shellcheck
```
Wichtig: Nicht blind alles wegdrücken. Wenn ShellCheck meckert, hat es meistens einen Punkt. Falls du eine Warnung bewusst ignorierst, dokumentiere sie direkt im Skript:
```bash
shellcheck disable=SC2086
rsync $RSYNC_OPTIONS "$SRC/" "$DST/"
```
Aber bitte nicht global mit der großen Keule alles deaktivieren. Das ist wie Monitoring ausschalten, weil Nagios nervt.
Praktisch ist auch eine `.shellcheckrc` im Repo:
```text
shell=bash
severity=warning
```
Damit ist klar, welche Shell gemeint ist und ab welcher Stufe die CI rot wird. Für Legacy-Skripte kannst du erstmal mit `severity=error` starten und später anziehen. Hauptsache, neue Fehler kommen nicht mehr rein.
Unser Fazit aus dem Selbstversuch: ShellCheck findet peinliche Bugs, bevor sie produktiv werden. Die CI sorgt dafür, dass das nicht vom Koffeinlevel einzelner Menschen abhängt. Genau so muss Admin-Automatisierung aussehen: langweilig, reproduzierbar und ohne Bash-Goblin im Serverraum.