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

Mitunter landet in Ihrem Terminal ein String aus Buchstaben, Ziffern und dem gelegentlichen +, / oder =, und Sie brauchen die echte Sache zurück. Ein in ein Ticket eingefügtes JWT, eine .b64-Datei im Anhang einer Support-E-Mail, ein Kubernetes-Secret, das sich liest wie Buchstabensuppe, eine PNG, die sich in einem HTML-data:-Tag versteckt. Dies ist der Praxisführer, um die Bytes in Bash und der Shell wieder herauszuholen - mit den Werkzeugen, die Sie mit ziemlicher Sicherheit bereits installiert haben.

Das Format in einem Atemzug: Base64 schreibt jeweils drei Bytes roher Daten als vier Zeichen aus einem Alphabet von 64 Zeichen um (A-Z, a-z, 0-9, plus + und /), und hängt am Ende ein oder zwei =-Zeichen 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 arbeitet das Format Schritt für Schritt durch, also verbringt dieser Artikel seine Zeit dort, wo sie hingehört, auf der Shell-Seite des Jobs.

Hier kommt die Plotwende: Es gibt nicht das eine base64-Kommando. Den Namen teilen sich ein GNU-C-Programm, ein Rust-Rewrite, ein BusyBox-Applet, ein BSD-Überbleibsel und ein OpenSSL-Werkzeug, dessen Flags sich auf wirklich gefährliche Weise überschneiden. Alle stimmen im Alphabet überein, aber nicht immer darüber, wie kaputter Input aussieht, und genau dort sterben Skripte. Also ist Schritt eins herauszufinden, wer antwortet, wenn Sie base64 tippen.

Kennen Sie den Dekodierer, mit dem Sie sprechen

Ein Kommando erzählt Ihnen fast die ganze Geschichte:

base64 --version

Je nach Maschine haben Sie es mit einem von diesen zu tun:

Was Sie sehen Was Sie haben Dekodier-Flag
base64 (GNU coreutils) 9.x Die klassische C-Implementation, auf den meisten Linux-Distributionen noch immer der Standard -d oder --decode
base64 (uutils coreutils) 0.8.x Das Rust-Rewrite von coreutils, das Standard-Userland der aktuellen Ubuntu-Releases -d (und, ungewöhnlicherweise, funktioniert auch -D)
BSD-artiger Usage-Text, kein Versions-Flag Das BSD-base64 auf macOS und den BSDs, abgeleitet vom alten bintrans-Tool -D (in dieser Familie heißt das kleingeschriebene -d debug, nicht decode)
BusyBox v1.x Das All-in-One-Binary von Alpine Linux und Embedded-Systemen -d

Achten Sie darauf, was in der Tabelle fehlt: OpenSSL. openssl base64 ist ein ganz anderes Tier, und sein -d-Flag bedeutet decrypt, nicht decode. Allein dieses Flag ist für mehr still erzeugte leere Ausgabedateien verantwortlich als jede andere Gewohnheit in diesem Artikel, also lernen wir es richtig kennen im Fallback-Abschnitt.

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

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

Vier One-Liner, die die meisten Tage abdecken

Dekodieren Sie einen String aus der Standard-Eingabe. Das ist der Zug, den Sie tausendmal machen werden, und printf hält die Shell davon ab, Ihren Payload zu verzieren:

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

Dekodieren Sie eine Datei. Jede ernsthafte Implementation akzeptiert ein FILE-Argument, und es ist der sauberste Weg, die Daten von der Quoting-Maschinerie der Shell fernzuhalten:

base64 -d payload.b64 > payload.bin

Dekodieren Sie aus einem Here-String. Der Here-String hängt ein abschließendes Zeilenende an, aber alle Dekodierer behandeln Zeilenenden als ignorbaren Leerraum, also ist das für kleine Blobs völlig sicher:

base64 -d <<< "SGVsbG8sIFdvcmxkIQ=="

Dekodieren Sie einen umgebrochenen, mehrzeiligen Blob mit einem Heredoc. Das Delimiter in einfache Anführungszeichen setzen hält die Shell davon ab, 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 -d in allen obigen Beispielen gegen -D aus, der Rest der Syntax ist identisch.

Unordneter Input ist die Norm

Das Base64, das Sie in der Wildnis treffen, ist selten eine saubere Zeile. Es trifft umgebrochen bei 76 Zeichen (MIME-Konvention) oder 64 Zeichen (PEM-Konvention) ein, exportiert aus Windows mit CRLF-Zeilenenden oder aus einem Chat-Fenster kopiert, mit losen Leerzeichen in der Mitte. Die gute Nachricht: Der Dekodierer schert sich nicht darum, wo die Zeilenumbrüche sind, solange es echte Zeilenenden sind.

Das universelle Heilmittel für jede Art von Umbruch ist, die Zeilenumbrüche vor dem Dekodieren wegzuschen:

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

Das Carriage Return ist der Sonderfall. Ein Zeilenende ist erlaubter Input, aber ein \r ist für strenge Dekodierer kein Zeilenende. Ein Blob, der ein Windows-System durchlaufen hat, bringt den GNU-Dekodierer zum Stolpern, der ein Teilzergebnis 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. Dasselbe Bad, tr -d '\r\n' vor dem Dekodieren, ist die portable Gewohnheit für jeden Input, den Sie nicht selbst erzeugt haben.

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

printf 'SGVs!bG8' | base64 -di

Das gibt Hello aus. Bevor Sie -i zur 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 verborgener Kanal ausgenutzt werden können, um Daten einzuschmuggeln, die nie in der dekodierten Ausgabe auftauchen. Greifen Sie zu -i, wenn ein Paste aus einem Dokument Interpunktion mitgebracht hat, nicht wenn Sie Daten verifizieren, denen Sie vertrauen.

Hier ist, wie die drei Haupt-Dekodierer an den Grenzen tatsächlich reagieren, auf dem 2026-Tooling (uutils 0.8.x, GNU coreutils 9.7, BusyBox 1.37):

Input 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"
CRLF-umbrachte Zeilen dekodiert sauber, Exit 0 Teil-Ausgabe, dann Fehler dekodiert sauber, Exit 0
SGVs!bG8, lose Interpunktion Fehler (mit -i: Hello) Teil-Ausgabe (mit -i: Hello) Teil-Ausgabe (ganz ohne -i-Flag)
SGV=, nicht-kanonische Rest-Bits Fehler, keine Ausgabe He ausgegeben, dann Fehler He, Exit 0
TQ==junk, Müll nach dem Padding Exit 0, dekodiert junk weiter Exit 0, dekodiert junk weiter M ausgegeben, dann "truncated input" (Exit 1)

Drei Erkenntnisse aus der Tabelle. Erstens gibt es keine universelle Regel für ungepolsterte Enden: BusyBox will, dass die Länge ein Vielfaches von vier ist, während GNU und uutils die legalen Reste annehmen, aber nur wenn die übrig gebliebenen Bits alle null sind (deswegen besteht Zg, aber nicht SGV). Zweitens schreiben GNU und BusyBox die Bytes, die sie schon dekodiert haben, bevor sie fehlschlagen, also behält ein Skript, das in eine Datei leitet und danach den Exit-Code prüft, fröhlich eine halb dekodierte Datei. Prüfen Sie immer den Exit-Status und behandeln Sie jede Datei, die ein fehlgeschlagenes Dekodieren hinterlässt, als verdächtig. Drittens, die letzte Zeile: uutils und GNU dekodieren junk nach dem == weiter und beenden mit 0, weil ihnen nichts sagt, dass der Stream hätte enden sollen. BusyBox ist die Ausnahme, gibt das eine Byte vor dem Padding aus und schlägt dann mit einem truncated-Input-Fehler fehl. Wenn nachfolgender Müll für Sie wichtig ist, validieren Sie die Form des Inputs, bevor Sie der Ausgabe vertrauen.

base64url: Das Alphabet von Tokens und URLs

RFC 4648, Abschnitt 5, definiert einen zweiten Dialekt: dieselbe 6-Bit-Mathematik, aber mit - und _ anstelle von + und /, und das Padding weggelassen, denn eine URL muss selten die exakte Byte-Länge anzeigen. Der RFC ist dabei klar: Diese Kodierung "sollte nicht als dasselbe wie die base64-Kodierung betrachtet werden". Wenn Sie schon einmal ein JWT angesehen haben, haben Sie den Dialekt bereits getroffen, denn seine Segmente sind base64url mit gestrichenem Padding.

Das Shell-Rezept ist ein Zweistufen-Tausch: übersetzen Sie die URL-sicheren Zeichen zurück in ihre Standard-Vettern, und dekodieren Sie dann:

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

Das liefert fe4f82 zurück, drei rohe Bytes, die zufällig gerade ein URL-Kostüm trugen. Der Tausch ist positionell, also zählt die Richtung: Kodieren geht mit tr '+/' '-_', Dekodieren mit tr '_-' '/+'. Vertauschen Sie die beiden, gibt es keinen Fehler, es werden nur still und leise andere Bytes produziert, und das ist die schlimmste Art von Bug.

Und jetzt die Falle, die Leute erwischt, die base64url wie ganz normales Base64 behandeln. Padding ist im Dialekt optional, und ein Segment, dessen Länge drei modulo vier ist, hat genau die Form, die strenge Dekodierer 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 schmuckloses JSON-Objekt, das ein Web-Server einen Moment zuvor signiert oder versiegelt hat. Segmente, deren Länge eins modulo vier ist, sind schon 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 in zwei Zeichen versteckt ist. Eine Warnung, bevor Sie Pipelines darauf aufbauen: Das GNU-basenc dieser Ära dekodiert sogar ungepolsterten base64url-Input (ein nacktes Zg) ohne Murren, während das uutils-basenc nach wie vor will, dass das Padding zuerst wiederhergestellt wird, 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, gemäß RFC 7515. Die ersten beiden sind reines JSON (der Header und die Claims des Payloads), also dekodieren sie direkt in lesbaren Text. Das dritte ist die Signatur, ein roher Binär-Digest, also lassen Sie es in Ruhe: Beim Dekodieren bekommen Sie 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, ohne dass ein Server beteiligt ist. Lesen Sie die Claims mit einem klaren Kopf darüber, was Dekodieren ist und was nicht: Es enthüllt, aber es verifiziert nicht. Die Signatur sagt nichts, bis der Server, der den Schlüssel hält, sie neu berechnet, und das ist die Aufgabe von openssl dgst (der Kodierungsartikel zeigt den kompletten Prägungstanz), nicht die von diesem Artikel. Ein häufiger Feldfehler ist, einen dekodierten Payload als Beweis dafür zu behandeln, dass ein Token gültig ist. Ein Angreifer kann Tokens ohne Signatur oder mit schwacher Signatur von Hand prägen, und ein Dekodierer liest alle davon fröhlich aus.

Dateien, Bytes und die Variablen-Wand

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

base64 -d photo.b64 > photo.png

Wenn das Original direkt neben Ihnen liegt, ist der 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 Checksummen:

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

Zwei passende Hashes und Ihr Dekodieren ist beweisbar exakt, was jede Menge Augenschein in einem Bildbetrachter oder Hex-Dump schlägt.

Shell-Variablen sind eine andere Geschichte, und sie sind eine Wand aus zwei Gründen. Command Substitution $(...) streicht jedes abschließende Zeilenende aus der Ausgabe, und sie kann gar keine NUL-Byte halten: bash gibt eine Warnung aus und wirft sie still und leise weg. Ein dreibytiger Payload von 41 00 42 zeigt beide Probleme in einer einzigen Demo:

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

Die Datei hält alle drei Bytes (41 00 42). Der Variablen-Weg nicht:

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

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

Wo Base64 in der echten Arbeit lauert

Sobald Dekodieren sich bequem anfühlt, fangen Sie an, das Format überall zu bemerken. Hier sind die Ecken der echten 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, nicht Verschlüsselung. Eines zurückzulesen ist ein klassischer One-Liner:

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

Git-Binary-Patches. Wenn ein Diff Binary-Files berührt, spuckt git diff --binary einen GIT binary patch-Block aus. Greifen Sie hier nicht zu base64 -d: Die Zeilen in dem Block sind git's eigene base85-artige Kodierung (jede Zeile beginnt mit einem Längen-Zeichen, A-Z oder a-z, gefolgt von base85-Daten), nicht Base64, und ein gewöhnlicher Dekodierer wird daran ersticken. Das richtige Werkzeug ist der Eigentümer des Formats:

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

Füttern Sie den Diff an 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 Zeilenumbrüche, dekodieren Sie, und Sie halten die Datei in der Hand:

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

PEM-Rüstung. Zertifikate und private Schlüssel wickeln ihr Base64 in Rahmen-Zeilen ein, die überhaupt kein Base64 sind. Wählen Sie den gepanzerten Block aus, streichen Sie die zwei Rahmen-Zeilen, und dekodieren Sie in das rohe DER-Binary:

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

Ersetzen Sie CERTIFICATE durch PRIVATE KEY oder durch das Etikett, das Ihre Datei trägt, die Form ist dieselbe.

MIME-E-Mail. Jeder Teil einer E-Mail mit Content-Transfer-Encoding: base64 ist umgebrochen bei 76 Zeichen mit CRLF-Zeilenenden, denn das ist, was RFC 2045 vorgibt. Die portable Kombination ist Bad plus Dekodieren:

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

Clipboard-Pastes. Text, der aus einem Browser, einem Chat-Fenster oder einem Dokument kopiert wurde, trifft mit losen Leerzeichen und einem abschließenden Zeilenende ein. Leerzeichen sind keine Alphabet-Zeichen, also lehnen strenge Dekodierer das Paste ab, und die Standard-Rettung ist, sie zuerst wegzulassen:

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

Zuerst Bytes: Charsets und Unicode

Der am häufigsten wiederholte Fehler in der Base64-Arbeit ist, in Zeichen zu denken, wenn das Format nur Bytes kennt. base64 -d gibt Ihnen rohe Bytes, und ob sie lesbaren Text werden, ist eine Entscheidung dessen, was sie als Nächstes liest. Diese Entscheidung ist ein Charset, und sie passiert nach dem Dekodieren, nie darin.

UTF-8 ist die Standard-Annahme und meist die richtige. Das Wort café in UTF-8 sind fünf Bytes, und das Dekodieren ist eine Freude:

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

Das ist 636166c3a9: caf plus die zwei UTF-8-Bytes c3 a9 für das é. Ältere Systeme allerdings geben Ihnen Latin-1- (ISO-8859-1) Bytes, in denen derselbe Buchstabe das einzelne Byte e9 ist. So ein Blob zu dekodieren und direkt in ein UTF-8-Terminal zu drucken, liefert Ihnen einen verdrehten 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 Tatsachen auf Byte-Ebene, die echte Debugging-Zeit sparen:

  • Ein UTF-8-BOM sind die drei Bytes ef bb bf, die zu 77u/ kodiert werden. Achten Sie auf das /, ein URL-feindliches Zeichen, genau die Art von Sache, für die base64url existiert. Wenn eine dekodierte Datei "unsichtbaren Müll vorneweg 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 Standard-Alphabet, das exakt so arbeitet, wie es entworfen wurde. In base64url-Kleidung wird daraus 8J-YgA.
  • Ungültige UTF-8-Sequenzen dekodieren einwandfrei als Bytes und werden dann als Müll oder als Ersatzzeichen angezeigt. Das ist kein Base64-Fehler, das Dekodieren hat seine Arbeit getan. xxd oder hexdump -C zeigt Ihnen, was die Bytes tatsächlich sind.
  • Die Locale Ihres Terminals entscheidet, wie sie 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 geändert.

Große Blobs: Streams, Splittings und Tempo

Base64 ist ein Stream-Format, und der Dekodierer arbeitet als wahre Streaming-Pipe: Eine 10-GB-Datei sitzt nie im Speicher, sie zieht einfach durch. Das macht die Dekodier-Seite in der Größe fast langweilig, und genau das wollen Sie.

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

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

Halten Sie ein mentales Modell für Größen: Die kodierte Form ist immer etwa ein Drittel größer als das Original, vier Zeichen pro drei Bytes. Wenn Ihnen also jemand sagt, die .b64-Datei sollte so groß sein wie das, was sie versteckt, hat er unrecht, und Sie können ihm jetzt sagen, um wie viel: Ein 300-MB-Payload trifft als rund 400 MB Text ein.

Tempo ist in der Praxis kein Thema. Das sind tabelle-gesteuerte Schleifen über ganz normalen Speicher, und auf einer modernen Maschine dekodiert ein 200-MB-Blob in ungefähr einem Zehntel einer Sekunde mit GNU, und selbst die langsamste der gängigen Implementierungen (BusyBox) ist nur ein paar Mal langsamer als das, immer noch deutlich unter zwei Sekunden. Der Speicherbedarf bleibt flach, egal wie groß der Input wird, denn nichts wird gepuffert.

Wenn die Maschine kein base64 hat

Die meisten Systeme haben mindestens eines der oben genannten Werkzeuge, und die meisten haben mehrere. Wenn Ihrer Plattform coreutils ganz fehlt (ein gestrippter Container, ein ungewöhnliches Gerät), sieht der Installationsweg so aus:

Plattform So bekommen Sie es Anmerkungen
Debian / Ubuntu vorinstalliert, apt install coreutils wenn gestrippt die aktuellen Ubuntu-Releases haben die uutils-Familie als Standard (seit 25.10), das GNU-Zwillingstier ist als gnubase64 erreichbar. Debian 13 liefert weiterhin GNU coreutils als Standard
RHEL / Fedora dnf install coreutils auf praktisch jedem Image vorinstalliert
Alpine apk add busybox (meistens bereits 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 Package-Manager eine Option ist, lesen die universellen Fallbacks unten alle von der Standard-Eingabe und schreiben Bytes auf die Standard-Ausgabe, 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, in dem das base64-Applet herauskompiliert wurde, funktioniert die alte Garde immer noch: uuencode -m erzeugt MIME-Base64, und sein Bruder liest es zurück:

busybox uudecode -o out.bin in.uu

Fallen, die ganze Nachmittage fressen

Alles unten ist Verhalten, das Sie im Feld treffen werden, an einem Ort gesammelt:

Falle Was passiert Die Lösung
openssl base64 -d allein macht still und leise nichts und beendet sich mit 0, weil dort -d Decrypt bedeutet openssl base64 -d -A -a, und behandeln Sie ein nullbyte-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 im Input GNU gibt ein Teilzergebnis aus und schlägt dann fehl. uutils und BusyBox akzeptieren es zuerst tr -d '\r\n', immer bei fremdem Input
Ungepolsterte Enden 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 sich mit 0. BusyBox gibt einen Fehler die Form des Inputs validieren, bevor Sie der Ausgabe vertrauen
Nicht-kanonische Rest-Bits, z.B. SGV= uutils und GNU lehnen ab (GNU nach Teil-Ausgabe). BusyBox dekodiert trotzdem der Input ist kaputt. Die Kodierung upstream neu erzeugen
Dekodierte Ausgabe in eine Variable lesen $(...) streicht abschließende Zeilenenden und kann gar keine NUL-Byte halten in eine Datei dekodieren, mit xxd inspizieren
-i auf nicht-vertrautem Input Korruption wird zum stillen Erfolg. Ignorierte Zeichen können versteckte Daten tragen streng dekodieren, den Fehler lesen, die Quelle fixen
Die zwei Alphabete verwechseln base64url als Standard zu dekodieren (oder umgekehrt) liefert falsche Bytes oder einen Fehler das Format vor dem Dekodieren kennen. Der Tausch ist tr '_-' '/+'
Ein dekodiertes Secret als Secret behandeln ein Kommando macht es rückgängig. Der RFC dokumentiert echte Fälle von geleakten Credentials echte Verschlüsselung, nicht Kodierung

Die OpenSSL-Zeile verdient einen eigenen Absatz, weil der Fehler so still ist. Bei OpenSSL 3.x ist das -d der Standalone-App deren allgemeine "decrypt"-Option, und die Base64-Verarbeitung ist ein separater Modus, der mit -a gewählt wird. Also liest openssl base64 -d Ihren Input, macht nichts, druckt nichts und beendet sich mit 0. Das funktionierende Dekodieren ist openssl base64 -d -A -a, wobei -A ihm sagt, dass der Input eine durchgehende Zeile ist. Wenn Sie OpenSSL zum Dekodieren benutzen müssen, behandeln Sie eine nullbyte-Ausgabe jedes einzelne Mal als Fehler.

Eine straffe Routine

Die Gewohnheiten, die Base64 daran hindern, je das Nachsehen zu haben:

  • Laut scheitern. Führen Sie Skripte mit set -euo pipefail aus und prüfen Sie Exit-Codes. Alle gängigen Dekodierer beenden sich mit 1 bei schlechtem Input. OpenSSL ist der laute, der still geworden ist, also prüfen Sie bei ihm 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. Binär nie mit den Augen prüfen.
  • Binär in Dateien, nie in Variablen. Abschließende Zeilenenden und NUL-Byte sind beide Opfer der Command Substitution.
  • Fremden Input waschen. Vor dem Dekodieren von allem, was eine Plattformgrenze überquert hat, tr -d ' \r\n'.
  • Standardmäßig streng bleiben. -i aus lassen, bis Sie gesehen haben, was genau falsch war. Ein strenger Fehler sagt Ihnen den Ort, ein nachsichtiger sagt Ihnen nichts.
  • Das Alphabet benennen. Standard-Base64 und base64url sind laut RFC 4648 verschiedene Kodierungen. Ein JWT als base64url dekodieren, einen E-Mail-Anhang als Standard, und nie Zeichen tauschen, ohne zu wissen warum.
  • Niemals das ausdrucken, was Sie gerade dekodiert haben. Der ganze Punkt des Formats in der Secrets-Welt ist Unsichtbarkeit, und der ganze Punkt eines Logs ist Sichtbarkeit. Diese beiden Ziele passen nicht zusammen.

Ein kleines portables 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 mit ihrem Versions-Banner ab, alle drei nehmen das kleingeschriebene Flag, und fällt bei allem anderen auf das BSD-Flag zurück, was genau die Vier-Wege-Split der realen Welt ist: GNU, uutils, BusyBox, BSD.

Wie die Shell das Dekodieren lernte

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

  • 1980, Berkeley. Mary Ann Horton schreibt uuencode und uudecode an der University of California, Berkeley, um Binary-Files (meist komprimierte) durch E-Mail zu tragen. Der Name bedeutet "Unix-to-Unix encoding", eine sichere Kodierung zum Verschieben von Dateien zwischen Unix-Systemen, die sich vielleicht kein Charset teilen. Jahrzehntelang ist das, nicht Base64, was Shell-Nutzer greifen.
  • 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, mit dem Macintosh einen Schritt dahinter, jede davon nimmt nur die Zeichen an, die ihr eigenes Terminal drucken kann.
  • 1993. MIME standardisiert Base64 für E-Mail (RFC 1521, später RFC 2045), mit dem 76-Zeichen-Zeilenumbruch, der den Default von base64 auch heute noch definiert.
  • 2003 und Oktober 2006. RFC 3548 räumt die Familie auf, und RFC 4648 ersetzt sie mit den Alphabeten und der strengen Dekodier-Regel, die dieser Artikel immer wieder zitiert, base64url inklusive.
  • 15. August 2006. coreutils 6.0 fügt das base64-Kommando selbst hinzu, und seine NEWS-Datei nennt es darin schlicht als "Funktionalität für base64-Kodierung und -Dekodierung (RFC 3548)". 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 Default-Zeilenumbruch, und genau deshalb kommt die -d-gegen--D-Split daher.
  • März 2024. coreutils 9.5 entspannt den Dekodierer: Padding ist beim Dekodieren nicht mehr Pflicht, und Kodierungen mit nicht-null Rest-Bits werden jetzt als Korruption diagnostiziert, statt still akzeptiert zu werden.
  • 2025. Das Rust-Rewrite von coreutils (uutils) wird der Standard auf den aktuellen Ubuntu-Releases. Gleicher Kommando-Name, gleiche Flags, ein neuer Motor mit eigenen Meinungen zu Grenzfällen, wie -D als Alias zu akzeptieren.

Kurioses, das sich lohnt

  • Das Kommando ist jünger als das Format. Base64 ist seit 1993 in der E-Mail, aber das base64-Kommando tauchte erst 2006 auf. Dreizehn Jahre lang haben Shell-Skripte diese Arbeit mit anderen Werkzeugen erledigt, und Sie können noch überall ihre Fingerabdrücke finden.
  • Ein Fossil im Hilfetext. Das uutils-base64 beschreibt sein Alphabet in der Hilfe immer noch als "RFC 3548", der ausrangierte Vorgänger von RFC 4648, während sein GNU-Pendant schon den aktuellen Standard zitiert. Ein winziges Fossil, das man nur sieht, wenn man die Hilfe liest.
  • Der teuerste stille no-op in der Werkzeugkiste. openssl base64 -d macht nichts und beendet sich mit 0. Eine ganze Debugging-Stunde, weg, und der Exit-Code-Test war bestanden.
  • BusyBox behält die Rest-Bits. Es dekodiert SGV= fröhlich, dessen Rest-Bits nicht-null und damit nicht-kanonisch sind, während sein GNU-Vetter über denselben Input einen Aufstand macht. Derselbe RFC, unterschiedliche Nerven.
  • Der Name des Formats ist auf jeder Maschine wahr. printf 'base64' | base64 ergibt YmFzZTY0 auf GNU, uutils, BusyBox und OpenSSL gleichermaßen. Das ist seit 2006 wahr und wird es immer sein.
  • Base85 ist nicht Base64. Die "binary patch"-Blöcke von Git sehen für das ungeübte Auge wie Base64 aus, aber die Längen-präfixierten Zeilen sind ein base85-artiger Dialekt für sich. Der Impersonator, der Leute auf einen grep-and-decode-Ausflug kostet.
  • Elf Zeichen, sechzig-vier Bits. Eine YouTube-Video-ID ist ein elf Zeichen langer base64url-String, eine 64-Bit-Zahl im URL-Kostüm, und deshalb kann sie in einer URL auftauchen, ohne ein einziges Prozent-Zeichen.
  • Dekodierer streiten über ein Zeichen. Ein einzelner String wie SGV= spaltet das Feld in drei Lager, wie die Verhaltens-Tabelle oben zeigt. Wenn ein Dekodieren an "offensichtlich validem" Input scheitert, stehen Sie wahrscheinlich auf der Rest-Bits-Linie, und die Kodierung war nie kanonisch.

Und wenn das nächste Mal ein String aus Buchstaben, Ziffern, Plus und Slash in Ihrem Terminal landet, kennen Sie die ganze Geschichte: welcher Dekodierer zuschaut, welches Alphabet spricht, wo die Zeilenenden versteckt sind und genau, wie Sie die Bytes zurückbekommen, intakt und Byte-für-Byte bewiesen, ohne eine Stunde an einem Carriage Return zu verlieren. Und wenn der Job die andere Richtung zeigt, wenn Sie Ihr eigenes Binary in einen Text-Umschlag für die Reise packen, deckt der verlinkte Base64-Kodierungsartikel unten diesen Ritus in derselben Tiefe ab.

Zuletzt aktualisiert: 2026-09-08

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