Files
claude-regelwerk/AI/Regelwerk/windows-shell.md
T
Pascal MichelandClaude Opus 5 f2ccec39d6 Automatischer Push: AI/Regelwerk/windows-shell.md
- AI/Regelwerk/windows-shell.md

Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-30 03:00:01 +01:00

60 lines
6.1 KiB
Markdown

---
type: resource
title: "Skripte und Shellbefehle unter Windows"
status: pending-review
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-10-29
---
# 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 <Distro>` 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.
- ⚠ Mit `python -I` wirkt die Variable nicht: `-I` schließt `-E` ein und ignoriert alle `PYTHON*`-Variablen. Dann `python -I -X utf8`. Das trifft auch `PYTHONDONTWRITEBYTECODE`: Soll kein `.pyc` im Projekt landen, zusätzlich `-B`. (`python-isoliert-ignoriert-pythonioencoding`)
## 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 <Distro> -- 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 <optionen> root@<host> bash -s < datei.sh"`. Verschachtelte Anführungszeichen kommen aus PowerShell nicht heil an. (`ssh-aus-powershell-als-datei-ueber-stdin`)
- **`SSH_ASKPASS` ohne Leerzeichen im Pfad, und vor der ersten Verbindung einmal probeweise starten.** Windows-OpenSSH startet askpass per `posix_spawnp`; scheitert das an einem Leerzeichen, schickt ssh ein **leeres Passwort** und erzeugt einen Fehlversuch am Ziel, der eine Login-Sperre füttert. **`UserKnownHostsFile` ohne `~` im Pfad:** ssh expandiert die Tilde auch im Windows-Kurzpfad (`C:\Users\NAME~1\…`) und schreibt dann still keinen Hostschlüssel; Langpfad mit `/` in Anführungszeichen nehmen. (`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/`