Codificar y decodificar una cadena
printf '%s' 'héllo wörld' | base64 # aMOpbGxvIHfDtnJsZA==
printf '%s' 'aMOpbGxvIHfDtnJsZA==' | base64 -d # héllo wörld
base64 codifica bytes, así que el resultado depende de la codificación de tu terminal. En cualquier Linux o macOS moderno es UTF-8.
El error clásico es echo, que añade un salto de línea al final:
echo 'héllo wörld' | base64 # aMOpbGxvIHfDtnJsZAo= (note the "o=")
echo -n hi | base64 # aGk=
echo -n funciona en Bash, pero no en todos los sh; printf '%s' es portable. Un here-string (base64 <<< "text") también añade un salto de línea. Si alguien te envía un Base64 que termina en Cg== u o=, probablemente contiene un salto de línea final; pégalo en el decodificador Base64 para comprobarlo.
Opciones de GNU (Linux) frente a BSD (macOS)
| Tarea | GNU coreutils (Linux) | macOS |
|---|---|---|
| Decodificar | -d, --decode | -D, --decode (las versiones recientes también -d) |
| Sin cortar líneas | -w 0 | por defecto |
| Cortar a N caracteres | -w N (por defecto 76) | -b N |
| Archivo de entrada | base64 file | base64 -i file o base64 < file |
| Archivo de salida | redirección > | -o file o redirección |
| Ignorar basura al decodificar | -i, --ignore-garbage | no disponible |
Las dos opciones -i significan cosas distintas: en macOS indica el archivo de entrada y en Linux ignora la basura. Los scripts portables deberían leer de stdin y escribir en stdout:
base64 < in.bin | tr -d '\n' > out.b64 # same output on Linux and macOS
base64 --decode < out.b64 > in-copy.bin
GNU base64 corta las líneas a 76 caracteres por defecto, lo que rompe cabeceras y variables de entorno:
head -c 60 /dev/zero | tr '\0' x | base64 -w 0
# eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4
Sin -w 0, la primera línea tiene 76 caracteres y el resto pasa a una segunda línea. Si necesitas líneas al estilo MIME, el corte por defecto es justo lo que quieres.
Base64 URL-safe
GNU coreutils 8.31 y posteriores incluyen basenc, que admite Base64URL. Conserva el relleno:
printf '%s' '<<???>>' | basenc --base64url # PDw_Pz8-Pg==
printf '%s' 'PDw_Pz8-Pg' | basenc --base64url -d # <<???>>
En macOS o en Linux antiguos, traduce los caracteres con tr:
printf '%s' '<<???>>' | base64 | tr '+/' '-_' | tr -d '=' # PDw_Pz8-Pg
Para decodificar hace falta la traducción inversa y, con los decodificadores estrictos, volver a poner el relleno:
s=PDw_Pz8-Pg
s=$(printf '%s' "$s" | tr -- '-_' '+/')
while [ $(( ${#s} % 4 )) -ne 0 ]; do s="$s="; done
printf '%s' "$s" | base64 -d # <<???>>
El -- impide que tr interprete -_ como una opción. Es la misma transformación que necesitan los JWT; el decodificador JWT se encarga de ello por ti. Más información en Base64 frente a Base64URL.
Codificar y decodificar archivos
base64 -w 0 hello.txt # aGVsbG8K
base64 -d <<< 'aGVsbG8K' > copy.txt
base64 -d payload.b64 > payload.pdf
base64 trabaja en flujo, así que el tamaño del archivo no importa: lee y escribe por bloques. Para crear un data URI de una imagen:
printf 'data:image/png;base64,%s' "$(base64 -w 0 logo.png)"
Para una cabecera HTTP Basic Auth:
printf 'Basic %s' "$(printf '%s' 'user:pass' | base64)" # Basic dXNlcjpwYXNz
El generador de cabeceras Basic Auth hace lo mismo sin dejar tu contraseña en el historial de la shell.
Validación, errores y códigos de salida
GNU base64 -d termina con código 1 y escribe base64: invalid input en stderr cuando encuentra un carácter incorrecto. Aun así, escribe todo lo que ha decodificado hasta ese punto, de modo que una decodificación fallida puede dejar un archivo a medias:
printf 'aGk=!!' | base64 -d # prints "hi", then: base64: invalid input
echo $? # 1 (without a pipe after it)
printf 'aGk=!!' | base64 -d -i # hi (garbage ignored, exit 0)
Resultados con coreutils 9.7:
| Entrada | Resultado |
|---|---|
aGk | hi, código 0 (se tolera la falta de relleno) |
"aGVs\nbG8K" | hello, código 0 (se ignoran los saltos de línea) |
aGl= | hi y después invalid input, código 1 |
a | invalid input, código 1 |
PDw_Pz8-Pg== | salida parcial, invalid input, código 1 |
Usa el código de salida para validar y decodifica a un archivo temporal para que un fallo no sobrescriba datos buenos:
if printf '%s' "$b64" | base64 -d > /tmp/out.bin 2>/dev/null; then
mv /tmp/out.bin result.bin
else
echo "invalid Base64" >&2
fi
En una tubería, $? es el código del último comando. Añade set -o pipefail si base64 -d no es el último. Cuando una cadena sacada de un log o de un correo no se deja decodificar, Reparar Base64 quita comillas, espacios y prefijos; la guía de errores explica cada fallo.
Otras herramientas de línea de comandos
openssl base64existe en casi todos los sistemas y se comporta igual en Linux y en macOS. Consulta Base64 con OpenSSL.python3 -m base64 -d fileypython3 -m base64 filefuncionan donde no hay coreutils; la salida se corta a 76 caracteres.- En Kubernetes, el patrón habitual es
kubectl get secret x -o jsonpath='{.data.password}' | base64 -d, o puedes usar el decodificador de secretos de Kubernetes.
Preguntas frecuentes
¿Por qué echo hello | base64 da un resultado distinto al de las herramientas online?
echo añade un salto de línea, así que codificas hello\n (aGVsbG8K) en lugar de hello (aGVsbG8=). Usa printf '%s' hello o echo -n hello.
¿Cómo evito que base64 corte las líneas?
En Linux, base64 -w 0. macOS no corta las líneas por defecto. Para un comando que se comporte igual en los dos, pasa la salida por tr -d '\n'.
¿Qué significa «base64: invalid input»?
GNU base64 -d encontró un carácter fuera del alfabeto o un relleno roto. Escribe los bytes que lleva decodificados, después el error, y termina con código de salida 1. Los culpables habituales son los - y _ de URL-safe, las comillas y los prefijos data:.
¿base64 -d en macOS es igual que en Linux?
Las versiones antiguas de macOS solo conocían -D (o --decode); las recientes también aceptan -d. Usa --decode en los scripts que deban funcionar en ambos.