Seit Emacs 23 ist UTF-8 der Default — der Alltag funktioniert „einfach". Aber sobald deutsche Sonderzeichen plötzlich kaputt aussehen, Windows-Dateien mit ^M enden oder ein BOM auftaucht, lohnt der Blick auf das Coding-System. Das ist der Mechanismus, mit dem Emacs Bytes auf Zeichen und Zeilenumbrüche abbildet — eine kleine, aber sehr alte Schicht direkt zwischen Datenträger und Buffer. Dieser Artikel erklärt das Konzept, zeigt, wie man Encoding und Zeilenende-Konvention manuell wechselt, übersetzt die Modeline-Kürzel und sammelt die Werkzeuge, mit denen Windows-Dateien sauber nach Unix konvertiert werden.
Was ein Coding-System ist
Ein Coding-System in Emacs ist kein reines „Encoding" im Sinne von „UTF-8 oder Latin-1", sondern ein Bündel aus drei Eigenschaften:
| Bestandteil | Beispiele | Bedeutung |
|---|---|---|
| Character Encoding | utf-8, latin-1, windows-1252, iso-8859-15, shift_jis | welche Bytes auf welche Unicode-Zeichen abgebildet werden |
| End-of-Line-Konvention | unix (\n), dos (\r\n), mac (\r) | wie Zeilenwechsel kodiert sind |
| Optionale Flags | -with-signature (BOM), automatische Dekompression bei .gz | Sonderfälle wie Byte-Order-Mark oder transparente gzip-Entpackung |
In der Schreibweise hängt Emacs Encoding und EOL mit Bindestrichen aneinander: utf-8-unix, utf-8-dos, latin-1-unix, windows-1252-dos, iso-8859-15-unix. Das Schema ist immer dasselbe — <encoding>-<eol>. Jedes Encoding kann mit jeder EOL-Konvention kombiniert werden; latin-1-dos ist genauso legitim wie utf-8-unix.
Einige Coding-Systeme bringen weitere Flags mit:
utf-8-unix UTF-8, Unix-EOL
utf-8-dos UTF-8, CRLF-EOL (typisch Windows)
utf-8-with-signature-unix UTF-8 mit BOM, Unix-EOL
utf-8-auto UTF-8 mit automatischer EOL-Erkennung
utf-16le-with-signature UTF-16 Little-Endian mit BOM (klassisch Windows)
latin-1-unix ISO-8859-1, Unix-EOL
iso-8859-15-unix ISO-8859-15 (Latin-9, mit €-Zeichen)
windows-1252-dos Windows-Codepage 1252, CRLF
no-conversion roh — keinerlei Konvertierung
prefer-utf-8 UTF-8 bevorzugt, mit Fallback bei nicht-UTF-8-BytesDie vollständige Liste zeigt M-x list-coding-systems — pro Eintrag mit Mnemonic-Buchstabe, Alias und Kurzbeschreibung. Für ein einzelnes Coding-System liefert M-x describe-coding-system Detailinformationen.
Wie Emacs das Coding-System einer Datei erkennt
Beim Öffnen einer Datei prüft Emacs in einer festen Reihenfolge, welches Coding-System gelten soll. Der Mechanismus ist mehrstufig — das ist der Grund, warum „einfach UTF-8" zu 99 % funktioniert, ohne dass du etwas konfigurieren musst.
| Stufe | Quelle | Wirkung |
|---|---|---|
| 1 | auto-coding-alist | harte Regel über Dateinamen-Muster — z. B. .tar → no-conversion |
| 2 | auto-coding-regexp-alist | Inhalts-Pattern in den ersten Bytes — z. B. BOM EF BB BF → utf-8-with-signature |
| 3 | File-Local-Variable | -*- coding: utf-8 -*- in der ersten oder letzten Zeile der Datei |
| 4 | auto-coding-functions | Funktionen, die in den Inhalt schauen — etwa der XML-Header <?xml encoding="..."?> |
| 5 | file-coding-system-alist | Regex über Dateinamen — z. B. \\.txt\\' → prefer-utf-8 |
| 6 | Default-Heuristik | prefer-utf-8 (seit Emacs 23) — testet UTF-8, fällt bei kaputten Bytes auf Latin-1 zurück |
Wichtig: Eine explizite coding:-Angabe in der Datei selbst überschreibt file-coding-system-alist — Datei-lokale Festlegung gewinnt. Die Default-Heuristik greift nur, wenn keine der oberen Stufen ein Coding-System bestimmt hat.
Wenn dich interessiert, wie Emacs eine bestimmte Datei entschieden hat: öffne sie, dann C-h v buffer-file-coding-system RET oder schau in die Modeline (siehe nächste Sektion). Welche Datei sich Emacs „nicht traut", siehst du an der Frage „Select coding system" beim Öffnen — sie erscheint, wenn die Auto-Detection keine eindeutige Antwort findet.
Encoding und EOL in der Modeline lesen
Der linke Block der Modeline zeigt Encoding und Zeilenende-Konvention auf engstem Raum. Die wichtigsten Mnemonics in Kurzform:
| Zeichen | Bedeutung |
|---|---|
U | UTF-8-Familie |
1 | ISO-Latin-1 (ISO-8859-1) |
= | no-conversion — bytegenau, keine Umwandlung |
- | Default / undecided |
J | Japanisch (ISO-2022-JP) |
S | Shift-JIS |
C | Chinesisch (Big5) |
Direkt hinter den drei Encoding-Zeichen steht ein Trenn-Zeichen, das die EOL-Konvention kodiert:
| Trenner | EOL-Konvention | Bytes | Typisches System |
|---|---|---|---|
: | Unix | LF | macOS, Linux, BSD |
\ | DOS | CRLF | Windows-Editoren |
/ | Mac (classic) | CR | Mac OS 9 und älter |
In der Praxis ergeben sich daraus drei Modeline-Stücke, die du immer wieder sehen wirst:
-UUU:---- UTF-8 auf Tastatur/Terminal/Datei, Unix-EOL (Default macOS/Linux)
-UUU\---- UTF-8, aber CRLF-EOL (Windows-Datei)
-11=:---- Latin-1 in/out, no-conversion fürs Schreiben (selten, aber möglich)
-===:---- no-conversion komplett — Binärdatei (z. B. ausgehexter Buffer)Die Reihenfolge der drei Encoding-Zeichen ist Eingabe — Ausgabe — Datei. In gut konfigurierten Setups stehen dort drei mal dasselbe Zeichen. Die vollständige Aufschlüsselung jedes Modeline-Felds — inklusive Modified-Indikator, Read-Only-Flag und Frame-Nummer — findest du im Artikel Modeline lesen.
Encoding manuell setzen oder ändern
Drei Befehle decken praktisch alle Coding-System-Wechsel ab. Für jeden gibt es ein klassisches Tastenkürzel (über die Prefix-Sequenz C-x RET) und einen sprechenden M-x-Namen.
| Befehl | Tastenkombi | Wirkung |
|---|---|---|
set-buffer-file-coding-system | C-x RET f | Coding-System fürs nächste Speichern des Buffers setzen |
revert-buffer-with-coding-system | C-x RET r | Datei neu laden und dabei mit anderem Coding-System interpretieren |
universal-coding-system-argument | C-x RET c | Coding-System nur für den unmittelbar folgenden Befehl erzwingen |
prefer-coding-system | M-x prefer-coding-system | globale Default-Präferenz für künftige Operationen verschieben |
recode-region | M-x recode-region | falsch dekodierten Bereich neu einlesen — Notbremse, wenn Stufe 1 schon misslang |
find-file-literally | M-x find-file-literally | Datei komplett ohne Konvertierung öffnen (Bytes wie sie sind) |
Die Faustregel zum Unterscheiden:
- Inhalt sieht kaputt aus →
revert-buffer-with-coding-system(Datei lesen mit anderem Encoding) - Inhalt sieht richtig aus, soll aber anders gespeichert werden →
set-buffer-file-coding-system(Datei schreiben mit anderem Encoding)
Der typische „Windows-Datei sauber nach Unix konvertieren"-Workflow sieht so aus:
- Datei mit C-x C-f öffnen.
- Modeline prüfen — steht da
\als Trenner? Dann ist es DOS-EOL. - C-x RET f oder M-x set-buffer-file-coding-system RET utf-8-unix RET.
- Speichern mit C-x C-s .
Beim nächsten Öffnen zeigt die Modeline : statt \ — die Datei ist konvertiert.
CRLF und Windows-Dateien
Das häufigste EOL-Problem im deutschen Entwickleralltag: Eine Datei kommt von einem Windows-Kollegen, aus einem Windows-Repo oder aus einem Windows-Build-Tool — und plötzlich zeigt Emacs am Zeilenende ein sichtbares ^M, oder die Modeline meldet dos statt unix. Was steckt dahinter?
Emacs unterscheidet zwei Fälle:
- Datei wird als
doserkannt: alles in Ordnung, das\r\nwird transparent abgebildet — du siehst keine^Mund kannst normal arbeiten. Die Datei behält beim Speichern CRLF. - Datei wird als
unixerkannt, enthält aber trotzdem CR-Bytes: dann interpretiert Emacs jedes\rals gewöhnliches Steuerzeichen und zeigt es als^Man. Das passiert oft bei gemischten Zeilenenden oder wenn ein anderer Modus die Auto-Detection überschrieben hat.
Vier Strategien, je nach Ziel:
| Ziel | Vorgehen |
|---|---|
| CRLF behalten (z. B. Windows-Tool-Datei) | nichts tun — Emacs zeigt sauber an und speichert wieder als CRLF |
| CRLF nach LF konvertieren | C-x RET f → utf-8-unix → C-x C-s |
| Per Datei fixieren (Datei-lokal) | erste Zeile mit -*- coding: utf-8-unix -*- ergänzen |
| Per Projekt erzwingen (plattformübergreifend) | .gitattributes mit * text=auto eol=lf oder .editorconfig mit end_of_line = lf |
Wenn die ^M schon im Buffer stehen und auch nach set-buffer-file-coding-system bleiben, liegt es daran, dass die Datei wirklich CR-Bytes enthält, nicht nur CRLF-Paare. In dem Fall hilft M-x replace-string RET C-q C-m RET RET — C-q C-m fügt im Minibuffer ein wörtliches Carriage-Return ein, das durch nichts ersetzt wird.
Für Projekte, in denen Windows- und Unix-Nutzer parallel arbeiten, ist die nachhaltigste Lösung eine .gitattributes-Datei im Repo-Root:
# Alle Textdateien beim Check-out auf LF zwingen
* text=auto eol=lf
# Windows-spezifische Skripte explizit als CRLF behalten
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlfDamit ist Emacs aus dem EOL-Spiel raus — Git liefert konsistente Bytes, und das Coding-System pro Buffer wird wieder zur Randnotiz.
Byte-Order-Mark (BOM) und UTF-16
Einige Windows-Tools — Notepad in älteren Versionen, manche Office-Exports, ältere .csv-Exporte aus Excel — speichern UTF-8 mit BOM (EF BB BF als erste drei Bytes). Emacs erkennt das und nutzt dann das Coding-System utf-8-with-signature statt utf-8. Beide sind funktional kompatibel, aber sie sind verschiedene Coding-Systeme:
| Coding-System | Bedeutung |
|---|---|
utf-8 | UTF-8, ohne BOM beim Speichern |
utf-8-with-signature | UTF-8, mit BOM beim Speichern |
utf-8-auto | UTF-8, BOM wird beim Lesen erkannt — geschrieben wird ohne BOM |
utf-16le-with-signature | UTF-16 Little-Endian mit BOM (Windows-Standard für UTF-16) |
utf-16be-with-signature | UTF-16 Big-Endian mit BOM |
utf-16le / utf-16be | UTF-16 ohne BOM (Endianness wird erzwungen) |
UTF-16 hat in der Regel immer ein BOM, weil sonst nicht entscheidbar ist, ob 00 41 für A oder für 䄀 steht. Bei UTF-8 ist das BOM technisch überflüssig — und in der Praxis schädlich:
#!/bin/bash-Shebangs werden ungültig, weil das BOM vor das#rutscht.- PHP gibt das BOM als „leere Ausgabe" mit aus und blockiert
header()-Aufrufe. - Manche XML-Parser, JSON-Parser und Build-Tools werfen Syntax-Fehler.
Wenn du eine UTF-8-Datei mit unerwartetem BOM erbst und es loswerden willst:
1. Datei öffnen — Modeline zeigt typischerweise ein "U" mit BOM-Hinweis
2. M-x set-buffer-file-coding-system RET utf-8-unix RET (ohne -with-signature)
3. C-x C-sUmgekehrt: wer ein BOM bewusst setzen will (z. B. weil ein Windows-Tool das erwartet), nutzt utf-8-with-signature-unix oder utf-8-with-signature-dos. Das ist eine bewusste, dokumentierte Entscheidung — und keine, die durch Zufall passieren sollte.
latin-1 und andere alte Encodings
Auch wenn UTF-8 heute der Default ist, begegnest du im Alltag immer wieder älteren Encodings. Die typischen Verdächtigen:
| Encoding | Wann es auftaucht |
|---|---|
iso-8859-1 (Latin-1) | deutsche Textdateien aus den 90ern und frühen 2000ern |
iso-8859-15 | wie Latin-1, aber mit Euro-Zeichen — typisch für EU-Behörden-Dokumente |
windows-1252 | Windows-Default vor UTF-8-Zeitalter, fast identisch mit Latin-1 |
cp850 / cp437 | DOS-Codepages — Logs, alte Batch-Skripte |
shift_jis, gb2312, big5 | japanische, chinesische und taiwanesische Texte aus älteren Tools |
ebcdic | Mainframe-Output (IBM) |
Das Vorgehen ist immer dasselbe — und ein gutes Beispiel für den Unterschied zwischen revert-buffer-with-coding-system und set-buffer-file-coding-system:
1. Datei öffnen — Umlaute sehen aus wie "ä" oder "?" oder "\223"
2. M-x revert-buffer-with-coding-system RET windows-1252 RET
→ Datei wird NEU GELADEN, jetzt sehen Umlaute korrekt aus
3. M-x set-buffer-file-coding-system RET utf-8-unix RET
→ ab jetzt wird als UTF-8 gespeichert
4. C-x C-s
→ Datei ist dauerhaft konvertiertWer sich nicht sicher ist, welches Encoding richtig ist, probiert nacheinander windows-1252, iso-8859-15, iso-8859-1 durch — bei deutschen Texten ist windows-1252 der häufigste Treffer, weil Windows-Tools historisch dieses Encoding statt strict-Latin-1 nutzten.
Globale Defaults sauber setzen
Für die meisten Setups ist die Empfehlung eindeutig: alles auf UTF-8 mit Unix-EOL als Default, Sonderfälle pro Datei oder pro Projekt regeln. Das Snippet dafür ist kurz:
;; Alles UTF-8 — Eingabe, Ausgabe, Datei, Prozesse
(set-default-coding-systems 'utf-8-unix)
(prefer-coding-system 'utf-8-unix)
(setq-default buffer-file-coding-system 'utf-8-unix)
;; Auch das Locale-Environment zwingt Emacs auf UTF-8 (Subprozesse, Clipboard)
(set-language-environment "UTF-8")
;; Clipboard auf macOS/Linux/Windows konsistent als UTF-8 interpretieren
(set-selection-coding-system 'utf-8)Wichtig zu verstehen: diese Zeilen ändern nicht das Auto-Detection-Verhalten. Dateien mit anderem Encoding werden weiterhin korrekt erkannt und behalten ihr Encoding beim Speichern — die Defaults greifen nur für neue Buffer und für Fälle, in denen Auto-Detection nichts Eindeutiges findet.
Was wohin gehört, erklärt der Artikel init.el und early-init.el ausführlich — in Kurzform: das Snippet kommt in ~/.config/emacs/init.el (oder ~/.emacs.d/init.el) und gilt nach dem nächsten Emacs-Start.
Wer auf Windows arbeitet und dort grundsätzlich CRLF will, ersetzt utf-8-unix durch utf-8-dos. Der robustere Weg ist allerdings, das Encoding auf UTF-8 zu fixieren und EOL pro Projekt über .gitattributes oder .editorconfig zu steuern — das funktioniert auch dann, wenn Kollegen mit anderen Editoren arbeiten.
Häufige Stolperfallen
Ein Coding-System steckt drei Dinge in einen Namen
utf-8-unix ist nicht „UTF-8" mit Bonus-Bindestrich, sondern Encoding (UTF-8) + EOL (Unix-LF) + ggf. Flags (z. B. -with-signature für BOM) in einer einzigen Zeichenkette. Wer das mitliest, versteht sofort, warum utf-8-unix und utf-8-dos unterschiedliche Coding-Systeme sind — obwohl beide UTF-8 sind.
Modeline-Trenner `:` vs. `\\` vs. `/` ist die EOL-Anzeige
Direkt nach den drei Encoding-Buchstaben steht ein einzelnes Zeichen — : für Unix, \ für DOS (CRLF), / für klassisches Mac (CR). Das ist leicht zu übersehen, weil es wie ein zufälliger Trenner aussieht. Wer den Trenner liest, sieht CRLF-Probleme, bevor sie weh tun.
`^M` heißt: Datei als unix geladen, enthält aber CR
Wenn Emacs am Zeilenende ^M (Caret-M) anzeigt, ist das Coding-System des Buffers unix, aber die Datei enthält trotzdem CR-Bytes. set-buffer-file-coding-system RET utf-8-unix + Speichern entfernt sie. Bei rein gemischten Zeilenenden hilft zusätzlich M-x replace-string RET C-q C-m RET RET.
BOM in UTF-8 bricht oft Shell-Skripte und Web-Tools
EF BB BF als Datei-Anfang macht #!/bin/bash ungültig, blockiert PHP-header()-Aufrufe und stolpert in manchen XML-Parsern. Beim Konvertieren bewusst utf-8 (ohne -with-signature) wählen — nicht aus Versehen die -with-signature-Variante stehen lassen.
`prefer-utf-8` ist klüger als pures `utf-8`
Der Default seit Emacs 23 ist prefer-utf-8 — das versucht UTF-8 zuerst und fällt bei nicht-dekodierbaren Bytes automatisch auf Latin-1 zurück. Wer (prefer-coding-system 'utf-8) schreibt statt 'utf-8-unix oder 'prefer-utf-8, verliert diesen Schutz und bekommt bei kaputten Bytes harte Lese-Fehler.
`utf-8-with-signature` und `utf-8` sind verschiedene Coding-Systeme
Auch wenn beide UTF-8 sind: das eine schreibt ein BOM, das andere nicht. Wer eine Datei mit BOM öffnet und einfach C-x C-s macht, schreibt das BOM wieder mit. Wer das BOM loswerden will, muss explizit auf utf-8 (ohne -with-signature) umstellen.
`.editorconfig` und `.gitattributes` schlagen jede init.el
Eine Encoding- und EOL-Policy im Repo (.gitattributes mit * text=auto eol=lf, oder .editorconfig mit charset = utf-8 und end_of_line = lf) wirkt für alle Editoren und alle Teammitglieder — robuster als persönliche init.el-Snippets, die nur den eigenen Emacs konfigurieren.
`revert-buffer-with-coding-system` liest neu — `set-buffer-file-coding-system` schreibt
Wenn der Inhalt im Buffer kaputt aussieht, ist revert-buffer-with-coding-system fast immer die Lösung — es lädt die Datei mit anderem Encoding neu. set-buffer-file-coding-system ändert nur, wie beim nächsten Speichern geschrieben wird, und repariert keinen falsch dekodierten Buffer.
Weiterführende Ressourcen
Externe Quellen
- GNU Emacs Manual — Coding Systems — die offizielle Konzept-Definition mit allen Mnemonics und EOL-Varianten.
- GNU Emacs Manual — Text Coding — die Befehle
set-buffer-file-coding-system,revert-buffer-with-coding-systemunduniversal-coding-system-argumentmit Tastenbelegung. - GNU Emacs Manual — Specify Coding — Detail zu File-Local-Variables,
coding:-Tags und Auto-Detection. - EditorConfig — Spezifikation — projektweite Encoding- und EOL-Policy, von Emacs (via
editorconfig-Paket) und vielen anderen Editoren respektiert. - Git — gitattributes —
text,eolundworking-tree-encoding, um EOL und Encoding auf Repo-Ebene zu normalisieren.