Subir un archivo
  1. base64hub
  2. Base64 en código
  3. Bash
Código

Base64 en Bash

El comando base64 hace el trabajo; Bash solo le pasa los datos por una tubería. GNU coreutils en Linux y la herramienta BSD de macOS usan opciones distintas. Las salidas de Linux de esta página son de GNU coreutils 9.7.

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)

TareaGNU coreutils (Linux)macOS
Decodificar-d, --decode-D, --decode (las versiones recientes también -d)
Sin cortar líneas-w 0por defecto
Cortar a N caracteres-w N (por defecto 76)-b N
Archivo de entradabase64 filebase64 -i file o base64 < file
Archivo de salidaredirección >-o file o redirección
Ignorar basura al decodificar-i, --ignore-garbageno 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:

EntradaResultado
aGkhi, 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
ainvalid 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 base64 existe en casi todos los sistemas y se comporta igual en Linux y en macOS. Consulta Base64 con OpenSSL.
  • python3 -m base64 -d file y python3 -m base64 file funcionan 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.

Sigue leyendo