--- type: resource title: "Skripte und Shellbefehle unter Windows" status: reference summary: "Verbindliche Regeln für Befehle und Skripte auf Pascals Windows-Maschine: welche Shell, welches Python, Kodierung, Zeilenenden, Quoting-Schichten, WSL und ssh." tags: [regelwerk, windows, werkzeuge] created: 2026-09-13 updated: 2026-09-13 --- # Skripte und Shellbefehle unter Windows Angeordnet am 2026-09-13. Laden, sobald du auf dieser Maschine ein Skript schreibst oder einen Shellbefehl ausführst, der mehr als ein einfaches Lesen ist. Die Regeln haben eins gemeinsam: Wer sie verletzt, bekommt fast nie eine Fehlermeldung, sondern ein plausibles falsches Ergebnis. Die Fallgeschichten stehen im Harness-Gedächtnis. Der Name der Erinnerung steht jeweils in Klammern. ## Welche Shell, welches Python - **Nie implizit `bash` aufrufen**, weder aus Python noch aus PowerShell. Windows sucht einen Programmnamen ohne Pfad zuerst in `System32`. Dort liegt der WSL-Starter, und seit dem 2026-09-03 startet er die Debian-Distribution statt der Git-Bash. Git-Bash sprichst du mit vollem Pfad an: `C:\Program Files\Git\bin\bash.exe`, nicht `…\usr\bin\`, weil der seine Coreutils nicht findet. WSL sprichst du mit `wsl -d ` an. `shutil.which("bash")` taugt nicht als Prüfung. (`bash-startet-unter-windows-den-wsl-stub`) - **`python`, nicht `python3`.** `python3` ist hier der Microsoft-Store-Stub. - **`PYTHONIOENCODING=utf-8`** vor jedem Python-Aufruf, der Umlaute oder Sonderzeichen ausgibt. Die Konsole fährt cp1252, und ohne die Variable bricht ein Skript mit `UnicodeEncodeError` ab oder zerlegt die Ausgabe. ## Skripte mit Prosa, Regex oder Backslashes - **Als Datei im Scratchpad anlegen, nie als Heredoc** und nie per `python -`. Jede Zeichenketten-Schicht frisst Backslashes, und aus einem Regex für „Backslash plus Pipe“ wird so eines, das alles trifft. (`backslash-frisst-sich-durch-zwei-schichten`) - **Jeder Prosa-String in Python wird dreifach quotiert**, auch einzeilige. Im Vault schließen deutsche Anführungszeichen mit einem geraden `"`, und das beendet in Python sonst den String. Vor dem Lauf `python -m py_compile datei.py`. (`python-heredoc-bricht-an-anfuehrungszeichen`) - **Kein `sed` für Muster mit `\|`, `\(` oder `\{`.** - **Nach jeder Ersetzung die geänderte Stelle ausgeben**, nicht nur den Exit-Code prüfen. Passt die Trefferzahl nicht zur Erwartung, ist das Muster kaputt. - **Keinen Commit in dieselbe Befehlszeile hinter ein Skript hängen**, dessen Ergebnis er beschreibt. ## PowerShell 5.1 - **Eine `.ps1` mit Nicht-ASCII-Zeichen bekommt eine UTF-8-BOM.** Ohne BOM liest PowerShell 5.1 die Datei als ANSI. Bash-Skripte bekommen nie eine BOM, sie bricht die Shebang-Zeile. (`powershell-liest-utf8-ohne-bom-als-ansi`) - **Wer nach Nicht-ASCII-Zeichen sucht, dekodiert die Datei ausdrücklich als UTF-8 und gibt Codepunkte aus** (`U+00B7`), nicht die Zeichen. `Select-String` mit Umlaut-Regex trifft über BOM-lose Dateien nie, und die Konsole stellt auch korrekte Zeichen als Fragezeichen dar. - **`return ,$wert`**, wenn eine Funktion ein Feld zurückgeben kann. Ohne das Komma zerfällt ein `byte[]` in Einzelbytes. Das Komma bekommt einen Kommentar, sonst vereinfacht es jemand weg. - **`.Contains()` statt `-like`**, wenn das Muster einen Backtick, `*`, `?` oder `[` enthält. - **Um native Aufrufe, deren Exit-Code entscheidet, `$ErrorActionPreference` lokal auf `Continue` setzen** und im `finally` zurücksetzen. Unter `Stop` wirft `2>&1` schon bei harmlosem stderr-Text, auch wenn der Prozess mit Exit-Code 0 endet. (`native-stderr-unter-erroractionpreference-stop`) ## Zeilenenden **Nie mit `grep` auf `\r` prüfen.** Die Git-Bash übersetzt beim Lesen `\r\n` zu `\n`, das Ergebnis `0` belegt also kein LF. Belastbar sind `tr -cd '\r' < datei | wc -c` (0 heißt LF), `od -c datei | head`, `file datei` und `git ls-files --eol datei`. (`grep-cr-in-git-bash-ist-blind`) ## WSL und entfernte Hosts - **`wsl -d -- bash -lc '…'` expandiert jedes `$` schon auf der Windows-Seite**, auch in einfachen Anführungszeichen. Pfade schreibst du deshalb literal, Exit-Codes gibst du im WSL-Teil selbst aus, oder du legst das Skript als Datei ab. (`wsl-bash-lc-expandiert-windowsseitig`) - **Befehle an entfernte Linux-Hosts laufen als LF-Datei über stdin:** `cmd /c "ssh.exe root@ bash -s < datei.sh"`. Verschachtelte Anführungszeichen kommen aus PowerShell nicht heil an. (`ssh-aus-powershell-als-datei-ueber-stdin`) - **In einem über stdin gestarteten Skript liest kein Befehl stdin.** Das heißt `ssh -n`, `ausearch … < /dev/null`, nie `| sh`. Prüfskripte legst du erst nach `/tmp` und startest sie dann. (`pruefskript-liest-stdin`) ## Geheimnisse in Ausgaben **Aus Umgebungsvariablen, Settings-Dateien und Transkripten gibst du nie Werte aus, nur Schlüssel, Zeilennummern und Längen.** Das gilt auch für jeden Auftrag an einen Subagenten, der solche Dateien berührt. Ein Agent, der eine Datei mit Klartext-Token liest, kopiert das Token in sein Transkript. Findest du ein Geheimnis im Klartext, empfiehlst du zuerst die Rotation. (`umgebungsvariablen-nur-als-laenge-ausgeben`, `settings-dateien-nicht-roh-an-subagenten`) ## Referenzen - [[CLAUDE|↑ Claude.md (Stamm)]] - [[AI/Regelwerk/codeworkflow|codeworkflow.md]]: Escaping-Schichten in Plänen - [[AI/Regelwerk/navigation|navigation.md]]: Werkzeuge unter `.vault-tools/`