Aus Linux-Magazin 09/2011

Shellskripte aus der Stümper-Liga – Folge 16: Decoding

Plaintext digital zu speichern oder zu übertragen erweist sich in der Praxis als bei Weitem nicht so trivial, wie es die Theorie vorsieht. Inkompatibel kodierte Dateien und unleserliche URL-Anfragen sind typische Alltagsphänomene. Manchmal vermag die Bash mit trickreichen Skripten zu helfen.

Kurz vor dem Millenniumswechsel fürchtete sich die kollektive IT-Welt vor dem Y2K-Problem: Die erste Stelle der vierstelligen Darstellung der Jahreszahl würde sich ändern, aber viele Programme hatten sie nur zweistellig oder als Differenz zu einem festen Datum kodiert. Es galt also, eine Menge Software anzupassen. Als dann der Wechsel kam, blieb der befürchtete Untergang der Zivilisation bekanntlich aus, kaum jemand hatte den Wechsel nennenswert bemerkt.

Aus dieser Erfahrung heraus zu folgern, dass jeder ähnlich gelagerte Paradigmenwechsel genauso schnell und problemarm über die Bühne geht, ist allerdings nicht zulässig. Ein langwieriges und hartnäckiges Ärgernis stellt beispielsweise die Kodierung von Daten und Dateien dar. Buchstaben, Ziffern und sonstige Zeichen zu speichern, also intern zu repräsentieren, erfordert, sie in Zahlen abzubilden. Diese Zuordnung ist zwangsläufig immer willkürlich, bedarf aber guter Abstimmung zwischen allen, die Daten erzeugen und nutzen wollen.

In der Anfangszeit der Computer gab es pro Plattform oft eine eigene Kodierung, etwa den BCD-Code auf IBMs Großrechnern, die zunächst jede Dezimalziffer von 0 bis 9 auf 4 Bit abbildeten. Darauf setzte dann der Ebcdic-Code (Extended Binary Coded Decimals Interchange Code) auf, der auch Zeichen beherrscht.

Glücklicherweise setzte sich in weiten Teilen der Industrie für lange Zeit Ascii durch, der American Standard Code for Information Interchange. 1968 definiert, gibt er auch heute noch die Reihenfolge vieler Zeichen in der internen Repräsentation vor. Obwohl viele Anwender von Ascii-Dateien sprechen, stimmt das seit gut 30 Jahren gar nicht: Der Code kennt nämlich nur 7 Bit und kann damit nur 128 unterschiedliche Zeichen darstellen. Spätestens seit dem Zeitalter des PC Anfang der 1980er Jahre organisieren aber fast alle Rechnerplattformen ihre Speicher in Bytes (oder Mehrfachen davon), die bekanntlich 8 Bit groß sind.

Kodierungs-Babel

Das achte Bit verdoppelte den Zeichenvorrat und bot nun auch Platz für Umlaute oder andere Sonderzeichen. Heute noch verbreitet sind die Kodierungsvarianten der Normenfamilie ISO-8859. Die Unterversion 1 enthält viele westeuropäische Sonderzeichen, ISO-8859-5 etwa kyrillische Zeichen. Auf vielen Rechnern kommt die Unternorm 15 vor, die ISO-8859-1 entspricht, aber zusätzlich das Eurozeichen enthält. Viele Tools nennen sie auch “Latin-9” oder “westeuropäisch”. Wer heute also von Ascii-Dateien spricht, mein oft diese Kodierung. Korrekter wäre die Bezeichnung “Textdatei”, wenn man sich nicht auf eine dieser Subvarianten festlegen möchte.

Von ISO-8859 zu UTF-8

Da auch die diversen ISO-8859-Normen nicht alle Schriftsprachen umsetzen, kam Ende der 1980er Jahre die Idee von Unicode auf, einer Kodierung, die alle gebräuchlichen und künftigen Sprachen abdecken sollte. Unicode ist nur eine Art Meta-Standard, denn er erlaubt mehrere Arten, um Zeichen auf Bytes abzubilden. Fast alle Betriebssysteme setzen heute im Auslieferungsstandard die Form UTF-8 ein. Dabei können einzelne Zeichen verschieden lange Repräsentationen erhalten: Die echten Ascii-Zeichen stehen an gleicher Stelle auch im UTF-8-Standard, womit jede Ascii-Datei zugleich eine korrekte und gleichbedeutende UTF-8-Datei ist. Das gilt allerdings nicht für Dateien, die nach ISO-8859 kodiert sind. Den Umlaut Ä repräsentiert die hexadezimale Bytefolge 0xC3, 0x84, wie

$ echo ${LANG}
de_DE.UTF-8
$ echo -n "Ä" | od -t x1
0000000 c3 84
0000002

leicht demonstriert [1]. Die meisten Programme sollten heute prinzipiell in der Lage sein, sowohl mit ISO- als auch mit UTF-Dateien umzugehen. Das Locale-System und die Umgebungsvariablen »LANG« sowie jene, die mit »LC_« beginnen, regeln die Zuordnung. Der Befehl »locale« zeigt die aktuelle Einstellung.

Fehlende Information

Das Problem fängt immer dann an, wenn unklar ist, welche Kodierung eine Datei tatsächlich verwendet. Zwar gibt es recht gute Heuristiken, um zu erraten, welche Zuordnung der Autor einer Datei verwendet hat – das Linux-Tool »file« ist ein Gattungsvertreter. Aber richtig sicher dürfen sich Anwender nur dann sein, wenn (am besten) der Verursacher die Kodierung explizit angibt. Sowohl das E-Mail-Protokoll SMTP als auch das Webprotokoll HTTP kennen daher den Header »Content-Type« , der darüber informiert. Wenn es darum geht, von einer Darstellung zur anderen zu wandeln, hilft das Werkzeug »recode« weiter, dessen aktuelle Version 281 Varianten kennt.

Als wäre die Welt nicht schon kompliziert genug, fiel in die Zeit des Umbruchs zwischen ISO und Unicode noch die Erfindung des Web. Es etablierte wieder eigene Zeichenfolgen, da dessen Gründerväter offenbar Zeichen außerhalb Ascii nicht trauten. Deswegen zeichnen viele heute noch ihre Umlaute in einem Anflug von Nostalgie nach dem Muster »Ä« aus. Das macht den Code nicht gerade wartbarer und ist völlig unnötig, gibt doch der HTML-Header das Encoding durch das Tag

<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />

ausreichend bekannt (siehe auch Abbildung 1). Wer es noch undurchsichtiger mag, verwendet die Zeichenfolge »&#xHH;« und fügt Hexadezimalziffern ein, die dann das Zeichen dieser Nummer in der im HTML-Header angegebenen Kodierung repräsentieren.

Abbildung 1: So lange Protokolle angeben, welches Encoding sie verwenden, funktioniert die zugehörige Software meist prima. Hier weist ein Header die Kodierung von Linux-Magazin Online als UTF-8 aus.

Abbildung 1: So lange Protokolle angeben, welches Encoding sie verwenden, funktioniert die zugehörige Software meist prima. Hier weist ein Header die Kodierung von Linux-Magazin Online als UTF-8 aus.

Eine auf den ersten Blick der HTML-Zuordnung ähnliche Schreibweise verwendet auch HTTP, das Transportprotokoll des Web. Hier leitet ein Prozentzeichen die Sequenz ein, gefolgt von exakt zwei hexadezimalen Ziffern. Anwender sollten sich jedoch davor hüten, die beiden Verfahren zu verwechseln: Das erste kommt im HTML-Text zum Einsatz, das zweite verwenden Webentwickler, um URLs zu kodieren, die besondere Symbole enthalten, etwa ein Leerzeichen. Browser verwenden diese Technik bei der HTTP-Parameterübergabe mit den Methoden »GET« oder »POST« . So wird aus »%20« ein Leerzeichen oder »%2F« wandelt sich zum Schrägstrich.

Obgleich dies eine der unleserlichsten Formen der Kodierung ist, lässt sie sich mit einem kleinen Trick ganz einfach mit der Bash enträtseln. Das in die Shell eingebaute Kommando »echo« beherrscht die Option »-e« , womit sie einige Sonderzeichen mit Backslash-Sequenzen ausgeben kann, etwa ein explizites Newline mit »echo -e “Apfel\nBirne”« . Ebenfalls erlaubt sind beliebige Zeichen, die der Anwender durch »\xHH« und zwei Hexadezimalzahlen HH angibt [2].

Magische Verwandlung

Dank der Nähe zur beschriebenen URL-Kodierung lässt sich das Präfix »%« einfach durch »\x« ersetzen, und schon gibt »echo -e« das Zeichen aus. Zum Ersetzen ist nicht einmal das externe Tool »sed« nötig, denn mit dem Expansions-Modifier »${Variable//Muster/Ersatz}« klappt das sogar Bash-intern. Wegen der beiden Schrägstriche nach der Variablen tauscht die Shell alle Vorkommen des Musters durch den Ersatz aus. Wer dagegen nur einen Slash verwendet, lässt die Bash nur ein einziges Mal substituieren.

Listing 1 liest zeilenweise eine Datei ein und gibt sie mit Hilfe von »echo -e« und der Substitution quasi im Klartext wieder aus. Dafür, dass das kurze Skript nach Unix-Tradition sowohl als Filter in einer Pipe benutzbar ist, der seinen Input von der Standardeingabe bezieht, als auch einen Dateinamen explizit entgegennimmt, sorgt Zeile 6: Ist das erste Argument (»1« ) definiert, liest die While-Schleife von dieser Datei. Andernfalls (Minuszeichen nach dem Variablennamen) verwendet die Bash die Standardeingabe aus dem Filedeskriptor 0 des eigenen Prozesses (»/proc/self/fd/0« ).

Listing 1

Decoder

01 #!/bin/bash
02
03 while read i
04 do
05 echo -e "${i//%/\x}"
06 done < ${1-/proc/self/fd/0}

Die Praxis erweist sich als überraschend schwierig

Das Thema Encoding nagt an den Nerven vieler Admins und Anwender. Obwohl der größte Teil aller Software technisch in der Lage ist, sowohl das alte ISO als auch das moderne Unicode und noch eine Reihe weiterer Kodierungen zu verarbeiten, fällt es Anwendern oft schwer, die richtigen Einstellungen zu treffen. Sehen sie sich dann mit unlesbaren Dateien konfrontiert, hilft die Bash mit ihren Substitutionen und der Ausgabeoption »-e« von »echo« in manchem Fall mit überraschend knappem Code weiter, etwa bei der URL-Kodierung.

Infos

  1. Kester Habermann, Nils Magnus, “Abschrift – Von ISO-8859-15 zu Unicode umsteigen”: Linux-Magazin 01/08, S. 76
  2. Bash-Builtin »echo« : http://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html#index-echo-134
DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 2 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben