CRLF vs LF Der Zeilendurchbruch-Fehler, der CI unterbricht
Ihr Shell-Skript funktioniert lokal, aber die CI-Umgebung wirft den Fehler 'falscher Interpreter: /bin/bash^M'. Dies ist das Problem mit den CRLF-Zeilenendungen. Erfahren Sie, was es verursacht, wie es erkannt wird und wie es dauerhaft mit .gitattributes behoben wird.
Dein Shell-Skript läuft perfekt auf deinem Laptop. Du pushst es auf GitHub. CI scheitert an einem rätselhaften /bin/bash^M: bad interpreter Fehler. Du hast gerade das unsichtbarste Bug in der Softwareentwicklung erlitten: falsche Zeilendurchbrüche.
Dieser Leitfaden erklärt, was CRLF und LF tatsächlich sind, warum die Mischung sie schleichend beschädigt und die genauen Schritte, um sicherzustellen, dass Zeilendurchbruch-Fehler nie mehr in deinen Pipeline gelangen.
Was sind CRLF und LF?
Jeder Textdatei benötigt eine Art, um das Ende einer Zeile zu kennzeichnen. Es existieren zwei Konventionen, die aus der Zeit der physischen Teletypenmaschinen stammen:
- LF (Line Feed) — ein
\nZeichen (Byte0x0A). Verwendet von Linux, macOS und allen Unix-abgeleiteten Systemen. - CRLF (Carriage Return + Line Feed) — zwei Zeichen,
\r\n(Bytes0x0D 0x0A). Verwendet von Windows und MS-DOS.
Die Namen stammen aus der Mechanik von Schreibmaschinen. Ein Zeilensprung verschiebt den Druckkopf zurück zum Anfang der Zeile. Ein Zeilenabsatz verschiebt das Papier um eine Zeile. Windows behielt beide; Unix entfernte den überflüssigen Zeilensprung.
Warum CRLF CI-Pipelines beschädigt
Auf Linux (wo praktisch alle CI-Runner ausgeführt werden), ist das \r kein Leerzeichen — es ist ein echtes Zeichen. Wenn ein Shell-Skript mit CRLF-Endungen gespeichert wird, endet jede Zeile mit \r vor dem Zeilenumbruch. Der Kernel interpretiert die Shebang-Zeile als #!/bin/bash\r und sucht nach einem Binärprogramm namens bash\r. Dieses Programm existiert nicht.
Der resultierende Fehler sieht wie folgt aus:
: bad interpreter: /bin/bash^M: No such file or directory
Der ^M ist die Art, wie Terminal-Displays den Zeilensprung-Charakter anzeigen. Er ist in den meisten Texteditoren unsichtbar, was dieses Bug so verwirrend macht.
Andere Orte, an denen CRLF schleichend Schaden verursacht
- Dockerfiles — Eine
RUNAnweisung mit CRLF fügt\rin jede Befehl ein, was String-Vergleiche und Dateipfade beschädigt. - Python-Skripte —
SyntaxError: unexpected character after line continuation characterwenn\folgt von\r\n. - .env-Dateien — Die Werte von Umgebungsvariablen erhalten einen trailing
\r, sodassAPP_ENV=production\rnicht mit dem erwartetenproduction. - CSV- und Datendateien — Parser, die Zeile für Zeile lesen, können
\rin das letzte Feld jeder Zeile einfügen. - SSH authorized_keys — Eine mit CRLF kodierte Schlüsseldatei wird schweigend vom SSH-Server abgelehnt.
- Git-Diffs — Jede Zeile erscheint geändert, was echte Änderungen in Rauschen unterdrückt.
Wie man Zeilendurchbruch-Probleme erkennt
Die meisten Editor verstecken Zeilendurchbrüche standardmäßig. Hier sind zuverlässige Methoden zum Überprüfen:
Mit cat oder hexdump
# Show ^M characters
cat -A yourfile.sh | head -5
# Hex dump to see 0x0d (CR) characters
hexdump -C yourfile.sh | head -10
Mit file-Befehl
file yourfile.sh
# CRLF output: yourfile.sh: ASCII text, with CRLF line terminators
# LF output: yourfile.sh: ASCII text
Mit grep
# Returns exit code 0 (found) if CRLF endings exist
grep -rlP "\r" . --include="*.sh" --include="*.py" --include="*.yml"
Wie man CRLF-Zeilendurchbrüche behebt
Option 1: dos2unix (schnellste einzeilige Lösung)
dos2unix entfernt die Zeilensprünge aus Dateien. Es ist auf allen wichtigen Linux-Distributionen verfügbar:
# Fix a single file
dos2unix yourscript.sh
# Fix all shell scripts recursively
find . -name "*.sh" -exec dos2unix {} \;
# Reverse: convert LF to CRLF (unix2dos)
unix2dos yourfile.sh
Option 2: sed (keine zusätzlichen Tools erforderlich)
# Remove carriage returns in-place
sed -i 's/\r//' yourscript.sh
# Or using tr
tr -d '\r' < input.sh > output.sh
Option 3: Beheben in VS Code oder JetBrains
In VS Code wird der Zeilendurchbruch-Modus in der Statusleiste (rechte untere Ecke) angezeigt. Klicken Sie darauf, um zwischen CRLF und LF für die aktuelle Datei umzuschalten. Um die Standardwerte für neue Dateien zu ändern, setzen Sie "files.eol": "\n" in Ihrer settings.json.
In JetBrains-IDEs gehen Sie zu Datei → Zeilenseparator um die aktuelle Datei zu ändern oder die Standardwerte in Editor → Code-Stil → Zeilenseparator.
Die richtige Lösung: .gitattributes
Einzeilige Lösungen sind nicht skalierbar. Die richtige Lösung ist eine .gitattributes Datei, die Git genau angibt, welche Zeilendurchbrüche zu erzwingen sind, unabhängig davon, welcher Editor oder welche Plattform die Entwickler verwenden.
# .gitattributes — commit this to the root of your repository
# Default: normalize all text files to LF in the repo
* text=auto eol=lf
# Explicitly enforce LF for scripts and configs
*.sh text eol=lf
*.bash text eol=lf
*.py text eol=lf
*.rb text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.json text eol=lf
*.env text eol=lf
Dockerfile text eol=lf
Makefile text eol=lf
# Windows-only files can keep CRLF
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
# Binary files — never touch line endings
*.png binary
*.jpg binary
*.gif binary
*.zip binary
*.pdf binary
Nachdem diese Datei hinzugefügt wurde, führen Sie folgenden Befehl aus, um Ihr gesamtes Repository in einem Schritt zu normalisieren:
git add --renormalize .
git commit -m "chore: normalize line endings via .gitattributes"
Git’s autocrlf-Einstellung — und warum sie oft Dinge verschlechtert
Git hat eine core.autocrlf Einstellung, die versucht, Zeilendurchbrüche automatisch umzuwandeln:
core.autocrlf=true— wandelt LF in CRLF um beim Checkout (Windows), CRLF in LF beim Commit. Intended für Windows-Nutzer.core.autocrlf=input— wandelt CRLF in LF um beim Commit, macht nichts beim Checkout. Sicherer für Mac/Linux.core.autocrlf=false— Git macht nichts. Was der Editor speichert, wird direkt kommittiert.
Das Problem: core.autocrlf ist eine lokale Einstellung, gespeichert in ~/.gitconfig. Jeder Entwickler auf deinem Team hat einen anderen Wert, wodurch Commit-Dateien von verschiedenen Maschinen unterschiedliche Zeilendurchbrüche erzeugen. Dies erzeugt ständig Rauschen in Diffs und intermittierende CI-Fehler, abhängig von dem Entwickler, der das letzte Mal eine Datei berührt hat.
Die allgemeine Regel: verwenden Sie .gitattributes um die Zeilendurchbruch-Politik im Repository festzulegen. Lassen Sie core.autocrlf sein, was jeder Entwickler hat — .gitattributes überschreibt es.
Hinzufügen eines CI-Schutzes
Auch mit .gitattributes in Ordnung, lohnt es sich, einen expliziten Check in CI hinzuzufügen, um jegliche Dateien zu erkennen, die durchschlüpfen. Ein zwei-Zeilen-Schritt deckt die meisten Fälle ab:
# In your CI workflow (GitHub Actions example)
- name: Check for CRLF line endings
run: |
if grep -rlP "\r" . --include="*.sh" --include="*.py" --include="*.yml" --include="Dockerfile"; then
echo "ERROR: CRLF line endings found. Run dos2unix on the above files."
exit 1
fi
Dieser Schritt scheitert laut an der Quelle — dem PR — anstatt schweigend beim Bereitstellen.
Schnellreferenz: CRLF vs LF
LF (\n) | CRLF (\r\n) | |
|---|---|---|
| Bytes | 0x0A | 0x0D 0x0A |
| Verwendet von | Linux, macOS, Unix | Windows, MS-DOS |
| Sicher für Shell-Skripte | Ja | Nein — beschädigt Shebang |
| Sicher für Dockerfile | Ja | NEIN |
| Sicher für .env-Dateien | Ja | Nein — fügt einem trailing \r zu Werten hinzu |
| Git-Empfehlung | Normalisierung auf LF im Repository | Nur für .bat/.cmd/.ps1 |
Erweiterungen installieren
IO-Tools zu Ihrem Lieblingsbrowser hinzufügen für sofortigen Zugriff und schnellere Suche
恵 Die Anzeigetafel ist eingetroffen!
Anzeigetafel ist eine unterhaltsame Möglichkeit, Ihre Spiele zu verfolgen. Alle Daten werden in Ihrem Browser gespeichert. Weitere Funktionen folgen in Kürze!
Unverzichtbare Tools
Alle Neuheiten
AlleAktualisieren: Unser neuestes Werkzeug wurde am 28. Apr. 2026 hinzugefügt
