Haben Sie mit dem Base64-Format zu tun? Dann ist diese Website genau das Richtige für Sie! Nutzen Sie unser superpraktisches Online-Tool, um Ihre Daten zu kodieren oder zu dekodieren.

Base64-Dekodierung in Bash: Ein vollständiger Leitfaden

Ab und zu landet eine Zeichenkette aus Buchstaben, Ziffern und dem einen oder anderen +, / oder = in Ihrem Terminal, und Sie brauchen das Original wieder. Ein JWT, das in ein Ticket kopiert wurde, eine .b64-Datei im Anhang einer Support-E-Mail, ein Kubernetes-Secret, das aussieht wie ein Buchstabenbrei, eine PNG, die sich in einem HTML-data:-Tag versteckt. Dies ist das Feldhandbuch, um die Bytes in Bash und der Shell wieder herauszuholen, mit den Werkzeugen, die Sie mit hoher Wahrscheinlichkeit bereits installiert haben.

Das Format in einem Atemzug: Base64 schreibt je drei Bytes roher Daten als vier Zeichen aus einem Alphabet von 64 Buchstaben um (A-Z, a-z, 0-9, dazu + und /) und hängt ein oder zwei = am Ende an, wenn die Anzahl der Bytes kein Vielfaches von drei ist. Dekodieren ist die schrumpfende Richtung dieses Tauschs: vier Zeichen gehen rein, drei Bytes kommen raus. Die Startseite dieser Site führt Schritt für Schritt durch das Format, also widmet sich dieser Artikel dem, wo er hingehört, der Shell-Seite der Arbeit.

Hier ist der Plot-Twist: Es gibt nicht das eine base64-Kommando. Den Namen teilen sich ein C-Programm von GNU, ein Neuschreiben in Rust, ein BusyBox-Applet, ein BSD-Relikt und ein OpenSSL-Werkzeug, dessen Flags sich auf wirklich gefährliche Weise überschneiden. Beim Alphabet sind sich alle einig, aber nicht immer darin, wie kaputte Eingabe aussieht, und genau dieser Unterschied ist es, wo Skripte sterben gehen. Also ist Schritt eins herauszufinden, wer antwortet, wenn Sie base64 tippen.

Den Decoder kennen, mit dem Sie sprechen

Ein einziges Kommando erzählt Ihnen die meiste Geschichte:

base64 --version

Je nach Maschine haben Sie es mit einer dieser Varianten zu tun:

Was Sie sehen Was Sie haben Dekodier-Flag
base64 (GNU coreutils) 9.x Die klassische C-Implementierung, auf den meisten Linux-Distributionen immer noch der Standard -d oder --decode
base64 (uutils coreutils) 0.8.x Die coreutils neu in Rust geschrieben, das Standard-Userland der aktuellen Ubuntu-Releases -d (und ungewöhnlicherweise funktioniert auch -D)
BSD-stiliger Usage-Text, kein Versions-Flag Das BSD-base64 auf macOS und den BSDs, abgeleitet vom alten bintrans-Tool -D (in dieser Familie bedeutet kleingeschriebenes -d debug, nicht decode)
BusyBox v1.x Das Alles-in-eins-Binary von Alpine Linux und eingebetteten Systemen -d

Beachten Sie, was in dieser Tabelle fehlt: OpenSSL. openssl base64 ist ein ganz anderes Tier, und sein -d-Flag bedeutet decrypt, nicht decode. Dieses einzelne Flag ist für mehr still leere Ausgabedateien verantwortlich als jede andere Gewohnheit in diesem Artikel, deshalb treffen wir es richtig im Fallback-Abschnitt.

Wenn Ihre Distribution mehr als eine Familie nebeneinander mitliefert (aktuelles Ubuntu tut das), zeigen ein paar Kommandos mehr das ganze Bild:

command -v base64
base64 --version 2>&1 | head -1

Vier One-Liner, die die meisten Tage abdecken

Eine Zeichenkette von der Standardeingabe dekodieren. Das ist der Zug, den Sie tausendmal machen werden, und das printf hält die Shell davon ab, Ihren Payload zu dekorieren:

printf '%s' "SGVsbG8sIFdvcmxkIQ==" | base64 -d

Eine Datei dekodieren. Jede ernsthafte Implementierung akzeptiert ein FILE-Argument, und das ist der sauberste Weg, die Daten fernzuhalten vom Quoting-Mechanismus der Shell:

base64 -d payload.b64 > payload.bin

Aus einem Here-String dekodieren. Der Here-String hängt ein abschließendes Zeilenende an, aber jeder Decoder behandelt Zeilenenden als ignorierbaren Leerraum, also ist das für kleine Blobs völlig sicher:

base64 -d <<< "SGVsbG8sIFdvcmxkIQ=="

Einen umgebrochenen, mehrzeiligen Blob mit einem Here-Doc dekodieren. Wenn Sie das Trennzeichen in einfache Anführungszeichen setzen, hindert das die Shell daran, irgendetwas darin zu interpretieren:

base64 -d <<'EOF'
SGVs
bG8s
IFdv
cmxk
IQ==
EOF

Alle vier geben Hello, World! aus. Auf macOS und den BSDs tauschen Sie in jedem Beispiel oben -d durch -D aus; der Rest der Syntax ist identisch.

Unordentliche Eingabe ist die Norm

Das Base64, auf das Sie in der Praxis stoßen, ist selten eine einzige saubere Zeile. Es kommt umgebrochen bei 76 Zeichen (MIME-Konvention) oder 64 Zeichen (PEM-Konvention), von Windows exportiert mit CRLF-Zeilenenden, oder aus einem Chat-Fenster kopiert mit verirrten Leerzeichen in der Mitte. Die gute Nachricht: Den Decoder stört es nicht, wo die Umbrüche sitzen, solange es echte Zeilenenden sind.

Das universelle Gegenmittel für jeden Umbruchstil ist, die Zeilenenden vor dem Dekodieren wegzuschen:

tr -d '\r\n' < blob.b64 | base64 -d

Carriage Returns sind der Sonderfall. Ein Zeilenende ist zulässige Eingabe, aber ein \r ist für die strengen Decoder kein Zeilenende. Ein Blob, der ein Windows-System durchquert hat, bringt den GNU-Decoder ins Stolpern, der ein Teilergebnis ausgibt und dann fehlschlägt; die Lösung ist, die Carriage Returns zuerst zu entfernen:

printf 'SGVs\r\nbG8s\r\n' | tr -d '\r' | base64 -d

Wenn Sie Fragmente wie Hel gefolgt von einem Fehler sehen, stehen Sie auf einem CRLF-Blob. Dieselbes Waschen, tr -d '\r\n', vor dem Dekodieren ist die portable Gewohnheit für jede Eingabe, die Sie nicht selbst erzeugt haben.

Für wirklich beschädigte Eingabe bieten GNU und uutils das -i-Flag (--ignore-garbage) an, das Zeichen außerhalb des Alphabets überspringt und dekodiert, was es kann:

printf 'SGVs!bG8' | base64 -di

Das gibt Hello aus. Bevor Sie aus -i eine Standardgewohnheit machen, wissen Sie, warum der Standard davor warnt: RFC 4648, Abschnitt 3.3, besagt, dass Implementierungen Daten, die Zeichen außerhalb des Alphabets enthalten, ablehnen müssen, weil ignorierte Zeichen als verdeckter Kanal ausgenutzt werden können, der Daten schmuggelt, die nie in der dekodierten Ausgabe auftauchen. Greifen Sie zu -i, wenn ein Einfügen aus einem Dokument Punktzeichen mitgebracht hat, nicht wenn Sie Daten verifizieren, denen Sie vertrauen.

So verhalten sich die drei großen Decoder an den Rändern tatsächlich, mit 2026er-Werkzeugen (uutils 0.8.x, GNU coreutils 9.7, BusyBox 1.37):

Eingabe uutils 0.8.x GNU 9.7 BusyBox 1.37
SGVsbG8sIFdvcmxkIQ==, sauber Hello, World!, Exit 0 Hello, World!, Exit 0 Hello, World!, Exit 0
SGVsbG8s, acht Zeichen, kein Padding Hello,, Exit 0 Hello,, Exit 0 Hello,, Exit 0
Zg, zwei Zeichen, kein Padding f, Exit 0 f, Exit 0 Fehler, "truncated input"
SGV, drei Zeichen, kein Padding Fehler, keine Ausgabe He ausgegeben, dann Fehler Fehler, "truncated input"
mit CRLF umgebrochene Zeilen dekodiert ohne Problem, Exit 0 Teil-Ausgabe, dann Fehler dekodiert ohne Problem, Exit 0
SGVs!bG8, verirrte Punktzeichen Fehler (mit -i: Hello) Teil-Ausgabe (mit -i: Hello) Teil-Ausgabe (gar kein -i-Flag)
SGV=, nicht kanonische Restbits Fehler, keine Ausgabe He ausgegeben, dann Fehler He, Exit 0
TQ==junk, Müll nach dem Padding Exit 0, fährt mit dem Dekodieren von junk fort Exit 0, fährt mit dem Dekodieren von junk fort M ausgegeben, dann "truncated input" (Exit 1)

Drei Erkenntnisse aus dieser Tabelle. Erstens: Es gibt keine universelle Regel für Enden ohne Padding: BusyBox verlangt, dass die Länge ein Vielfaches von vier ist, während GNU und uutils die zulässigen Reste akzeptieren, aber nur wenn die Restbits alle null sind (daher besteht Zg und SGV nicht). Zweitens: GNU und BusyBox schreiben die Bytes, die sie bereits dekodiert haben, bevor sie fehlschlagen, also behält ein Skript, das in eine Datei umleitet und danach erst den Exit-Code prüft, gelassen eine halb dekodierte Datei. Prüfen Sie immer den Exit-Status und behandeln Sie jede Datei, die ein fehlgeschlagenes Dekodieren zurücklässt, als verdächtig. Drittens: diese letzte Zeile: uutils und GNU dekodieren nach dem == weiter junk und beenden mit 0, weil nichts ihnen sagt, der Stream hätte enden sollen; BusyBox ist die Ausnahme, es gibt das eine Byte vor dem Pad aus und schlägt dann mit einem truncated-input-Fehler fehl. Wenn Sie sich um angehängten Müll kümmern, validieren Sie die Form der Eingabe, bevor Sie der Ausgabe vertrauen.

base64url: Das Alphabet von Tokens und URLs

Abschnitt 5 von RFC 4648 definiert einen zweiten Dialekt: dieselbe 6-Bit-Mathematik, aber mit - und _ anstelle von + und /, und das Padding wird weggelassen, weil eine URL selten die genaue Byte-Länge ankündigen muss. Der RFC ist dabei bestimmt: Diese Kodierung "sollte nicht mit der base64-Kodierung gleichgesetzt werden". Wenn Sie sich schon einmal ein JWT angesehen haben, haben Sie den Dialekt bereits getroffen, denn seine Segmente sind base64url mit entferntem Padding.

Das Shell-Rezept ist ein Tausch in zwei Schritten: Übersetzen Sie die URL-sicheren Zeichen zurück zu ihren Standard-Vettern und dekodieren Sie dann:

printf '%s' "_k-C" | tr '_-' '/+' | base64 -d | xxd -p

Das liefert fe4f82, drei rohe Bytes, die zufällig ein URL-Outfit trugen. Der Tausch ist positionell, also kommt es auf die Richtung an: Beim Kodieren läuft es als tr '+/' '-_', beim Dekodieren als tr '_-' '/+'. Wenn man sie verwechselt, kommt kein Fehler; es werden nur still und leise andere Bytes produziert, und das ist die schlimmste Art von Bug.

Und jetzt die Falle, die alle fängt, die base64url wie normales Base64 behandeln. Padding ist im Dialekt optional, und ein Segment, dessen Länge drei modulo vier ist, hat genau die Form, die die strengen Decoder unter die Lupe nehmen. Der robuste Zug ist, die fehlenden =-Zeichen zuerst wiederherzustellen, und das ist eine kleine Funktion:

b64url_decode () {
  local s=$1
  local n
  n=$(printf '%s' "$s" | wc -c | tr -d '[:space:]')
  while [ $(( n % 4 )) -ne 0 ]; do
    s="${s}="
    n=$(( n + 1 ))
  done
  printf '%s' "$s" | tr '_-' '/+' | base64 -d
}
b64url_decode "eyJzdWIiOiJob21lciJ9"

Die letzte Zeile gibt {"sub":"homer"} aus, ein schlichtes JSON-Objekt, das ein Web-Server einen Moment zuvor signiert oder versiegelt hat. Segmente, deren Länge eins modulo vier ist, sind von Anfang an fehlerhaft, und keine Menge an Padding rettet sie, also ist die Ablehnung dieses Falls durch die Funktion ein Feature.

Es gibt auch einen nativen Weg in GNU coreutils: basenc, der größere Bruder von base64, versteht den Dialekt direkt:

printf '%s' "Zg==" | basenc --base64url -d

Das gibt f aus, das eine Byte, das sich in zwei Zeichen versteckt. Eine Warnung, bevor Sie darauf Pipelines bauen: Das GNU-basenc dieser Ära dekodiert sogar base64url-Eingabe ohne Padding (ein nacktes Zg) ohne Murren, während das uutils-basenc immer noch das Padding zuerst wiederhergestellt haben will, wie das obige Beispiel zeigt. Die kleine Funktion oben funktioniert überall, und deshalb ist sie die portable Wahl.

Ein JWT öffnen

Ein JSON Web Token besteht aus drei base64url-Segmenten, die durch Punkte verbunden sind, laut RFC 7515. Die ersten zwei sind schlichtes JSON (der Header und die Payload-Claims), also dekodieren sie direkt zu lesbarem Text. Das dritte ist die Signatur, eine rohe binäre Prüfsumme, also lassen Sie es in Ruhe: Dekodieren liefert Ihnen die Signatur-Bytes, keine Nachricht.

token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MiJ9.abc123"
b64url_decode "$(printf '%s' "$token" | cut -d. -f2)"

Das gibt {"sub":"42"} aus, den subject-Claim, ganz ohne Server. Lesen Sie die Claims mit klarem Kopf darüber, was Dekodieren ist und was nicht: Es enthüllt, es verifiziert nicht. Die Signatur sagt nichts, bis der Server, der den Schlüssel hält, sie neu berechnet, und das ist eine Aufgabe für openssl dgst (der Kodierungsartikel zeigt den gesamten Prägungstanz), nicht für diesen. Ein häufiger Feldfehler ist, eine dekodierte Payload als Beweis zu behandeln, dass ein Token gültig ist; ein Angreifer kann unsignierte oder schwach signierte Tokens von Hand prägen, und ein Decoder liest sie alle fröhlich aus.

Dateien, Bytes und die Variablen-Mauer

Dekodieren übergibt Ihnen rohe Bytes. Sie können einen englischen Satz buchstabieren oder die Mitte einer PNG, einer Shared Library oder eines zip-Archivs sein. Die Datei ist der einzige Ort in einem Shell-Skript, an dem Bytes völlig sicher sind, also ist der Standard-Workflow, in eine Datei zu dekodieren und dann zu vergleichen:

base64 -d photo.b64 > photo.png

Wenn das Original neben Ihnen liegt, ist ein Byte-für-Byte-Vergleich der einzige Beweis, der zählt:

cmp photo.png photo.png.orig && echo "byte-for-byte identical"

Wenn das Original weit weg ist, vergleichen Sie stattdessen Prüfsummen:

sha256sum expected.bin
base64 -d blob.b64 | sha256sum

Zwei übereinstimmende Hashes, und Ihre Dekodierung ist beweisbar exakt, was jede Menge Augenmaß in einem Bildbetrachter oder Hex-Dump schlägt.

Shell-Variablen sind eine andere Geschichte, und sie sind eine Mauer aus zwei Gründen. Die Kommandosubstitution $(...) entfernt jedes abschließende Zeilenende aus der Ausgabe, und sie kann überhaupt kein NUL-Byte halten: Bash gibt eine Warnung aus und wirft sie still und leise weg. Ein dreibyter Payload aus 41 00 42 zeigt beide Probleme in einer Demo:

printf 'QQBC' | base64 -d > out.bin
xxd out.bin

Die Datei hält alle drei Bytes (41 00 42). Der Weg über die Variable nicht:

v=$(printf 'QQBC' | base64 -d)
printf '%s' "$v" | wc -c

Sie bekommen 2, mit einer Warnung auf Standardfehler über das ignorierte NUL-Byte. Die Lektion ist kurz: Wenn die Daten binär sein könnten, dekodieren Sie sie in eine Datei, untersuchen Sie sie mit xxd und lassen Sie sie niemals durch eine Variable.

Wo Base64 sich in echter Arbeit versteckt

Sobald Dekodieren sich bequem anfühlt, fangen Sie an, das Format überall zu bemerken. Hier sind die Ecken echter Shell-Arbeit, in denen es auftaucht, jeweils mit dem exakten Zug.

Kubernetes-Secrets. Jedes Feld unter .data in einem Secret ist Base64, und die offizielle Doku betont, dass das Kodierung ist, keine Verschlüsselung. Eines wiederzulesen ist ein klassischer One-Liner:

kubectl get secret db-creds -o jsonpath='{.data.password}' | base64 -d; echo

Binäre Git-Patches. Wenn ein Diff binäre Dateien berührt, gibt git diff --binary einen GIT binary patch-Block aus. Greifen Sie hier nicht nach base64 -d: Die Zeilen in diesem Block sind git's eigene base85-artige Kodierung (jede Zeile beginnt mit einem Längenzeichen, A-Z oder a-z, gefolgt von base85-Daten), kein Base64, und ein einfacher Decoder wird daran ersticken. Das richtige Werkzeug ist der Besitzer des Formats:

git diff --binary | grep -a -A2 'GIT binary patch'

Speisen Sie das Diff in git apply oder git am, und lassen Sie sie das Auspacken erledigen.

Data-URIs. Ein in HTML oder CSS eingebettetes Bild sieht aus wie data:image/png;base64,iVBOR.... Streichen Sie alles bis einschließlich Komma weg, waschen Sie die Zeilenenden, dekodieren Sie, und Sie halten die Datei in der Hand:

cut -d, -f2- icon.uri | tr -d '\r\n' | base64 -d > icon.png

PEM-Umhüllung. Zertifikate und private Keys wickeln ihr Base64 in Rahmenzeilen ein, die überhaupt kein Base64 sind. Wählen Sie den umhüllten Block, werfen Sie die beiden Rahmenzeilen weg und dekodieren Sie zur rohen DER-Binärdatei:

awk '/BEGIN CERTIFICATE/{f=1;next} /END CERTIFICATE/{f=0} f' cert.pem | tr -d '\r\n' | base64 -d > cert.der

Tauschen Sie CERTIFICATE gegen PRIVATE KEY oder welches Label Ihre Datei auch trägt aus; die Form ist dieselbe.

MIME-E-Mails. Jeder Teil einer E-Mail mit Content-Transfer-Encoding: base64 ist bei 76 Zeichen umgebrochen, mit CRLF-Zeilenenden, weil das genau das ist, was RFC 2045 vorschreibt. Die portable Kombination ist Waschen plus Dekodieren:

tr -d '\r\n' < attachment.b64 | base64 -d > attachment.bin

Einfügen aus der Zwischenablage. Text, der aus einem Browser, einem Chat-Fenster oder einem Dokument kopiert wurde, kommt mit verirrten Leerzeichen und einem abschließenden Zeilenende. Leerzeichen sind keine Alphabet-Zeichen, also lehnen die strengen Decoder das Einfügen ab; die Standard-Rettung ist, sie zuerst wegzulassen:

tr -d ' \r\n' < pasted.b64 | base64 -d

Zuerst Bytes: Charsets und Unicode

Der häufigste Fehler in der Base64-Arbeit ist, in Zeichen zu denken, wenn das Format nur Bytes kennt. base64 -d übergibt Ihnen rohe Bytes, und ob daraus lesbarer Text wird, ist eine Entscheidung, die das trifft, was sie als Nächstes liest. Diese Entscheidung ist ein Charset, und sie passiert nach der Dekodierung, nie innerhalb.

UTF-8 ist die Standardannahme und meistens die richtige. Das Wort café in UTF-8 ist fünf Bytes, und die Dekodierung ist ein Vergnügen:

printf 'Y2Fmw6k=' | base64 -d | xxd -p

Das ist 636166c3a9: caf plus die beiden UTF-8-Bytes c3 a9 für das é. Ältere Systeme geben Ihnen dagegen Latin-1-Bytes (ISO-8859-1), wo derselbe Buchstabe das einzelne Byte e9 ist. Dekodieren Sie einen solchen Blob und geben Sie ihn direkt in ein UTF-8-Terminal aus, bekommen Sie einen verschandelten Buchstaben; die Lösung ist, die Bytes mit iconv neu zu interpretieren, bevor irgendetwas anderes sie sieht:

base64 -d latin1.b64 | iconv -f ISO-8859-1 -t UTF-8 > utf8.txt

Ein paar Fakten auf Byte-Ebene, die echte Debugging-Zeit sparen:

  • Ein UTF-8-BOM sind die drei Bytes ef bb bf, die zu 77u/ kodiert werden. Beachten Sie das /, ein URL-feindliches Zeichen, genau die Art von Dingen, für die es base64url gibt. Wenn eine dekodierte Datei "unsichtbaren Müll am Anfang hat", prüfen Sie die ersten drei Bytes mit xxd.
  • Ein Emoji wie 😀 ist vier UTF-8-Bytes und wird zu acht Base64-Zeichen, 8J+YgA==. Das + darin ist das Standardalphabet, das exakt wie designed arbeitet; in base64url-Kleidung wird daraus 8J-YgA.
  • Ungültige UTF-8-Sequenzen dekodieren einwandfrei als Bytes und werden dann als Müll oder Ersetzungszeichen angezeigt. Das ist kein Base64-Fehler; die Dekodierung hat ihre Arbeit gemacht. xxd oder hexdump -C zeigt Ihnen, was die Bytes tatsächlich sind.
  • Die Locale Ihres Terminals entscheidet, wie es diese Bytes rendert. "Das Terminal zeigt Müll" ist eine Aussage über die Anzeige, nicht über die Daten. Die Bytes haben sich auf der Reise nicht verändert.

Große Blobs: Streams, Aufteilung und Geschwindigkeit

Base64 ist ein Stream-Format, und der Decoder arbeitet als echte Streaming-Pipe: Eine 10-GB-Datei liegt nie im Speicher; sie zieht einfach hindurch. Das macht die Dekodierseite bei Größe fast langweilig, und genau das wollen Sie.

Wenn ein großer Blob für den Transfer in Chunks aufgeteilt wurde (eine E-Mail-Grenze, eine Ticket-Anhanggröße, eine IM-Nachricht), ist das Zusammenbauen einfach ein cat in der richtigen Reihenfolge, gefolgt vom üblichen Waschen:

cat part_* | tr -d '\r\n' | base64 -d > big.bin

Behalten Sie ein mentales Modell für Größen bei: Die kodierte Form ist immer etwa ein Drittel größer als das Original, vier Zeichen pro drei Bytes. Also wenn Ihnen jemand sagt, die .b64-Datei sollte dieselbe Größe haben wie das Ding, das sie versteckt, hat er unrecht, und Sie können es ihm jetzt exakt sagen: Ein 300-MB-Payload kommt als etwa 400 MB Text an.

Geschwindigkeit ist in der Praxis kein Thema. Das sind tabelle-gesteuerte Schleifen über gewöhnlichen Speicher, und auf einer modernen Maschine dekodiert ein 200-MB-Blob mit GNU in etwa einem Zehntel einer Sekunde, und selbst die langsamste der gängigen Implementierungen (BusyBox) ist nur wenige Male langsamer, trotzdem deutlich unter zwei Sekunden. Der Speicherverbrauch bleibt flach, egal wie groß die Eingabe wird, weil nichts gepuffert wird.

Wenn die Maschine kein base64 hat

Die meisten Systeme haben mindestens eines der obigen Werkzeuge, und die meisten haben mehrere. Wenn Ihre Plattform ganz ohne coreutils dasteht (ein ausgedünnter Container, ein ungewöhnliches Appliance), sehen die Installationswege so aus:

Plattform So holen Sie es Notizen
Debian / Ubuntu vorinstalliert; apt install coreutils wenn ausgedünnt Die aktuellen Ubuntu-Releases haben die uutils-Familie als Standard (seit 25.10), mit dem GNU-Zwilling erreichbar als gnubase64; Debian 13 liefert weiterhin GNU coreutils als Standard mit
RHEL / Fedora dnf install coreutils in praktisch jedem Image vorinstalliert
Alpine apk add busybox (meist schon vorhanden) busybox base64 -d; kein -i-Flag
macOS eingebaut; brew install coreutils für die GNU-Version BSD-Flags: -D zum Dekodieren, -b für die Zeilenbreite; brew gibt Ihnen gbase64

Und wenn überhaupt kein Paketmanager eine Option ist, lesen alle universellen Fallbacks unten von der Standardeingabe und schreiben Bytes auf die Standardausgabe, also passen sie in dieselben Pipelines:

openssl base64 -d -A -a < in.b64 > out.bin
perl -MMIME::Base64 -0777 -ne 'print decode_base64($_)' < in.b64 > out.bin
python3 -c 'import base64, sys; sys.stdout.buffer.write(base64.b64decode(sys.stdin.buffer.read()))' < in.b64 > out.bin

Auf einem BusyBox-System, bei dem das base64-Applet rauskompiliert wurde, funktioniert die alte Garde immer noch: uuencode -m erzeugt MIME-Base64, und sein Bruder liest es wieder ein:

busybox uudecode -o out.bin in.uu

Fallen, die ganze Nachmittage fressen

Alles Unten ist Verhalten, das Sie im Feld antreffen werden, an einem Ort gesammelt:

Falle Was passiert Die Lösung
openssl base64 -d für sich allein macht stumm nichts und beendet mit 0, weil -d dort Decrypt bedeutet openssl base64 -d -A -a, und behandeln Sie ein Null-Byte-Ergebnis als Fehler
Dekodieren auf macOS mit -d Das BSD-base64 lehnt das Flag ab (oder behandelt es als debug) -D, oder installieren Sie coreutils für gbase64
CRLF-Zeilenenden in der Eingabe GNU gibt ein Teilergebnis aus und schlägt dann fehl; uutils und BusyBox akzeptieren es tr -d '\r\n' zuerst, immer bei fremder Eingabe
Enden ohne Padding BusyBox lehnt jeden Rest ab; GNU und uutils akzeptieren nur kanonische Enden das fehlende =-Padding vor dem Dekodieren wiederherstellen
Müll nach dem Padding, z. B. TQ==junk uutils und GNU dekodieren weiter und beenden mit 0; BusyBox meldet einen Fehler die Form der Eingabe validieren, bevor Sie der Ausgabe vertrauen
Nicht kanonische Restbits, z. B. SGV= uutils und GNU lehnen ab (GNU nach Teil-Ausgabe); BusyBox dekodiert trotzdem die Eingabe ist beschädigt; erzeugen Sie die Kodierung upstream neu
Dekodierte Ausgabe in eine Variable lesen $(...) entfernt abschließende Zeilenenden und kann überhaupt keine NUL-Bytes halten in eine Datei dekodieren, mit xxd untersuchen
-i auf nicht vertrauenswürdiger Eingabe Beschädigung wird zu einem stillen Erfolg; ignorierte Zeichen können versteckte Daten tragen streng dekodieren, den Fehler lesen, die Quelle beheben
Die beiden Alphabete verwechseln base64url als Standard dekodieren (oder umgekehrt) liefert falsche Bytes oder einen Fehler das Format kennen, bevor Sie dekodieren; der Tausch ist tr '_-' '/+'
Ein dekodiertes Secret als Secret behandeln ein einziges Kommando macht es rückgängig; der RFC dokumentiert echte Vorfälle von auslaufenden Zugangsdaten echte Verschlüsselung, keine Kodierung

Die OpenSSL-Zeile verdient einen eigenen Absatz, weil der Fehler so still ist. Bei OpenSSL 3.x ist das -d der Standalone-App ihre allgemeine "decrypt"-Option, und die Base64-Verarbeitung ist ein separater Modus, der mit -a gewählt wird. Also liest openssl base64 -d Ihre Eingabe, tut nichts, gibt nichts aus und beendet mit 0. Das funktionierende Dekodieren ist openssl base64 -d -A -a, wobei -A sagt, die Eingabe sei eine durchgehende Zeile. Wenn Sie OpenSSL für das Dekodieren benutzen müssen, behandeln Sie eine Ausgabe mit null Bytes als Fehler, jedes einzelne Mal.

Eine stramme Routine

Die Gewohnheiten, die Base64 davon abhalten, jemals die Oberhand über Sie zu gewinnen:

  • Laut scheitern. Führen Sie Skripte mit set -euo pipefail aus und prüfen Sie Exit-Codes. Alle gängigen Decoder beenden mit 1 bei schlechter Eingabe; OpenSSL ist der Laute, der still geworden ist, also prüfen Sie für ihn zusätzlich, dass die Ausgabe nicht leer ist.
  • Den Round-Trip beweisen. cmp oder sha256sum zwischen erwarteten und wiederhergestellten Bytes ist der einzige Beweis, der zählt. Niemals binär mit bloßem Auge prüfen.
  • Binär in Dateien, niemals in Variablen. Abschließende Zeilenenden und NUL-Bytes sind beide Opfer der Kommandosubstitution.
  • Fremde Eingabe waschen. tr -d ' \r\n' vor dem Dekodieren von allem, was eine Plattformgrenze überquert hat.
  • Standardmäßig streng bleiben. Halten Sie -i aus, bis Sie gesehen haben, was genau falsch war; ein strenges Versagen sagt Ihnen die Stelle, ein nachsichtiges sagt Ihnen nichts.
  • Das Alphabet benennen. Standard-Base64 und base64url sind laut RFC 4648 verschiedene Kodierungen. Dekodieren Sie ein JWT als base64url, einen E-Mail-Anhang als Standard, und tauschen Sie niemals Zeichen, ohne zu wissen warum.
  • Niemals ausgeben, was Sie gerade dekodiert haben. Der ganze Sinn des Formats in der Secret-Welt ist Unsichtbarkeit; der ganze Sinn eines Logs ist Sichtbarkeit. Diese zwei Ziele mischen sich nicht.

Ein kleiner portabler Shim für die Frage "welches Flag will diese Maschine":

case "$(base64 --version 2>&1 | head -2)" in
  *uutils*|*GNU*|*BusyBox*) b64d () { base64 -d; } ;;
  *)                        b64d () { base64 -D; } ;;
esac
b64d < in.b64 > out.bin

Die case-Anweisung fängt die GNU-, uutils- und BusyBox-Familien anhand ihres Versionsbanners ab - alle drei nehmen das kleingeschriebene Flag - und fällt auf alles andere auf das BSD-Flag zurück, und das ist genau die Vier-Wege-Aufteilung der realen Welt: GNU, uutils, BusyBox, BSD.

Wie die Shell das Dekodieren lernte

Das Format ist alt; das Kommando, das Sie tippen, nicht. Eine kurze Zeitlinie der Shell-Seite der Geschichte:

  • 1980, Berkeley. Mary Ann Horton schreibt uuencode und uudecode an der University of California, Berkeley, um binäre Dateien (meist komprimierte) durch E-Mail zu tragen. Der Name bedeutet "Unix-zu-Unix-Kodierung", eine sichere Kodierung für den Transport von Dateien zwischen Unix-Systemen, die kein gemeinsames Charset haben müssen. Jahrzehntelang ist das, nicht Base64, was Shell-Nutzer anwenden.
  • Das Dial-up-Zeitalter. Die frühesten Base-Kodierungen reiten auf demselben Problem: uuencode auf UNIX, BinHex auf dem TRS-80 und dem Apple II, das Macintosh einen Schritt hinterher, jede nimmt nur die Zeichen an, die ihr eigenes Terminal drucken konnte.
  • 1993. MIME standardisiert Base64 für E-Mail (RFC 1521, später RFC 2045), mit dem Zeilenumbruch bei 76 Zeichen, der bis heute den base64-Standard definiert.
  • 2003 und Oktober 2006. RFC 3548 räumt die Familie auf, und RFC 4648 ersetzt sie mit den Alphabeten und der strengen Dekodierregel, die dieser Artikel immer wieder zitiert, base64url eingeschlossen.
  • 15. August 2006. coreutils 6.0 fügt das base64-Kommando selbst hinzu, seine NEWS-Datei bescheinigt es schlicht als "base64-Kodierung und -Dekodierung (RFC 3548) Funktionalität". Vor diesem Datum griffen Shell-Nutzer auf Linux zu openssl base64, uuencode -m, Perl oder Python, und deshalb nehmen so viele alte Skripte an, OpenSSL sei die einzige Option in der Stadt.
  • OS X 10.7. macOS liefert sein eigenes base64 mit, die BSD-Variante mit dem -D-Flag und ohne Standard-Zeilenumbruch, und genau da kommt die -d-gegen--D-Aufteilung her.
  • März 2024. coreutils 9.5 lockert den Decoder: Padding ist beim Dekodieren nicht mehr erforderlich, und Kodierungen mit nicht nullen Restbits werden jetzt als Beschädigung diagnostiziert, statt still akzeptiert zu werden.
  • 2025. Das coreutils neu in Rust geschrieben (uutils) wird der Standard in aktuellen Ubuntu-Releases. Derselbe Kommandoname, dieselben Flags, ein neuer Motor mit eigenen Randmeinerien, wie das Akzeptieren von -D als Alias.

Kuriositäten, die sich zu behalten lohnen

  • Das Kommando ist jünger als das Format. Base64 ist seit 1993 in der E-Mail, aber das base64-Kommando erschien erst 2006. Dreizehn Jahre Shell-Skripte haben diese Arbeit mit anderen Werkzeugen erledigt, und Sie können ihre Fingerabdrücke überall noch finden.
  • Ein Fossil im Help-Text. Das uutils-base64 beschreibt sein Alphabet in seiner Hilfe immer noch als "RFC 3548", der ausrangierte Vorgänger von RFC 4648, während sein GNU-Bruder schon den aktuellen Standard zitiert. Ein winziges Fossil, nur sichtbar, wenn Sie die Hilfe lesen.
  • Der teuerste stille No-Op im Werkzeugkasten. openssl base64 -d tut nichts und beendet mit 0. Eine ganze Debugging-Stunde, weg, und der Exit-Code-Test hat bestanden.
  • BusyBox behält die Restbits. Es dekodiert fröhlich SGV=, dessen Restbits nicht null und damit nicht kanonisch sind, während sein GNU-Cousin wegen derselben Eingabe einen Wutanfall bekommt. Gleicher RFC, andere Nerven.
  • Der Name des Formats ist auf jeder Maschine wahr. printf 'base64' | base64 gibt auf GNU, uutils, BusyBox und OpenSSL gleichermaßen YmFzZTY0 aus. Das ist seit 2006 wahr und wird es immer sein.
  • Base85 ist nicht Base64. Gits "binary patch"-Blöcke sehen für das ungelernte Auge wie Base64 aus, aber die Zeilen mit Längenvorangabe sind ein base85-artiger Dialekt für sich. Der Scharlatan, der Menschen einen Umweg über grep und Dekodieren kostet.
  • Elf Zeichen, vierundsechzig Bits. Eine YouTube-Video-ID ist eine 11-stellige base64url-Zeichenkette, eine 64-Bit-Zahl in URL-Kleidung, deshalb kann sie in einer URL auftauchen, ohne ein einziges Prozentzeichen.
  • Decoder sind sich über ein Zeichen uneinig. Eine einzige Zeichenkette wie SGV= spaltet das Feld in drei Lager, wie die Verhaltens-Tabelle oben zeigt. Wenn eine Dekodierung an "offensichtlich gültiger" Eingabe fehlschlägt, stehen Sie wahrscheinlich auf der Restbits-Linie, und die Kodierung war nie kanonisch.

Also das nächste Mal, wenn eine Zeichenkette aus Buchstaben, Ziffern, Plus und Slash in Ihrem Terminal landet, kennen Sie die ganze Geschichte: Welcher Decoder zuschaut, welches Alphabet spricht, wo die Zeilenenden sich verstecken, und genau wie Sie die Bytes zurückbekommen, heil und bytegenau bewiesen, ohne eine Stunde an ein Carriage Return zu verlieren. Und wenn die Arbeit die andere Richtung zeigt, Ihr eigenes Binär in eine Text-Enveloppe für die Reise zu packen, deckt der verknüpfte Base64-Kodierungsartikel unten diesen Ritus in derselben Tiefe ab.

Zuletzt aktualisiert: 2026-09-08

Verwandter Artikel: Base64-Kodierung in Bash: Ein vollständiger Leitfaden