Codificar e decodificar uma string
printf '%s' 'héllo wörld' | base64 # aMOpbGxvIHfDtnJsZA==
printf '%s' 'aMOpbGxvIHfDtnJsZA==' | base64 -d # héllo wörld
O base64 codifica bytes, então o resultado segue a codificação do seu terminal. Em qualquer Linux ou macOS moderno, isso é UTF-8.
O erro clássico é o echo, que acrescenta uma quebra de linha:
echo 'héllo wörld' | base64 # aMOpbGxvIHfDtnJsZAo= (note the "o=")
echo -n hi | base64 # aGk=
O echo -n funciona no Bash, mas não em todo sh; o printf '%s' é portável. Uma here-string (base64 <<< "text") também acrescenta quebra de linha. Se alguém lhe mandar Base64 terminado em Cg== ou o=, provavelmente há uma quebra de linha no final; cole no decodificador Base64 para conferir.
Flags do GNU (Linux) vs BSD (macOS)
| Tarefa | GNU coreutils (Linux) | macOS |
|---|---|---|
| Decodificar | -d, --decode | -D, --decode (versões recentes também -d) |
| Sem quebra de linha | -w 0 | padrão |
| Quebrar a cada N caracteres | -w N (padrão 76) | -b N |
| Arquivo de entrada | base64 file | base64 -i file ou base64 < file |
| Arquivo de saída | redirecionar com > | -o file ou redirecionar |
| Ignorar lixo ao decodificar | -i, --ignore-garbage | não disponível |
As duas flags -i significam coisas diferentes: no macOS ela indica o arquivo de entrada, no Linux ela ignora lixo. Scripts portáveis devem ler da stdin e escrever na stdout:
base64 < in.bin | tr -d '\n' > out.b64 # same output on Linux and macOS
base64 --decode < out.b64 > in-copy.bin
O base64 do GNU quebra em 76 caracteres por padrão, o que estraga headers e variáveis de ambiente:
head -c 60 /dev/zero | tr '\0' x | base64 -w 0
# eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4
Sem -w 0, a primeira linha tem 76 caracteres e o resto vai para uma segunda linha. Se você precisa de linhas no estilo MIME, a quebra padrão é exatamente o que quer.
Base64 URL-safe
O GNU coreutils 8.31 e mais novos incluem o basenc, que suporta Base64URL. Ele mantém o preenchimento:
printf '%s' '<<???>>' | basenc --base64url # PDw_Pz8-Pg==
printf '%s' 'PDw_Pz8-Pg' | basenc --base64url -d # <<???>>
No macOS ou em Linux mais antigo, traduza com tr:
printf '%s' '<<???>>' | base64 | tr '+/' '-_' | tr -d '=' # PDw_Pz8-Pg
Para decodificar, é preciso fazer a tradução inversa e, para decodificadores rígidos, recolocar o preenchimento:
s=PDw_Pz8-Pg
s=$(printf '%s' "$s" | tr -- '-_' '+/')
while [ $(( ${#s} % 4 )) -ne 0 ]; do s="$s="; done
printf '%s' "$s" | base64 -d # <<???>>
O -- impede que o tr leia -_ como uma opção. É a mesma transformação de que os JWTs precisam; o decodificador de JWT faz isso por você. Mais em Base64 vs Base64URL.
Codificar e decodificar arquivos
base64 -w 0 hello.txt # aGVsbG8K
base64 -d <<< 'aGVsbG8K' > copy.txt
base64 -d payload.b64 > payload.pdf
O base64 trabalha em fluxo, então o tamanho do arquivo não importa; ele lê e escreve em blocos. Para montar uma data URI de uma imagem:
printf 'data:image/png;base64,%s' "$(base64 -w 0 logo.png)"
Para um header HTTP Basic Auth:
printf 'Basic %s' "$(printf '%s' 'user:pass' | base64)" # Basic dXNlcjpwYXNz
O gerador de header Basic Auth faz o mesmo sem deixar a sua senha no histórico do shell.
Validação, erros e códigos de saída
O base64 -d do GNU sai com status 1 e imprime base64: invalid input na stderr quando encontra um caractere inválido. Mesmo assim, ele escreve tudo o que decodificou até ali, então uma decodificação que falha pode deixar um arquivo parcial para trás:
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 com o coreutils 9.7:
| Entrada | Resultado |
|---|---|
aGk | hi, exit 0 (preenchimento ausente tolerado) |
"aGVs\nbG8K" | hello, exit 0 (quebras de linha ignoradas) |
aGl= | hi, depois invalid input, exit 1 |
a | invalid input, exit 1 |
PDw_Pz8-Pg== | saída parcial, invalid input, exit 1 |
Use o status de saída para validar e decodifique para um arquivo temporário, assim uma falha não sobrescreve dados bons:
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
Num pipeline, $? é o status do último comando. Acrescente set -o pipefail se o base64 -d não for o último. Quando uma string tirada de um log ou de um e-mail não decodifica, o Reparar Base64 remove aspas, espaços e prefixos; o guia de erros explica cada falha.
Outras ferramentas de linha de comando
- O
openssl base64existe em quase todo sistema e se comporta igual no Linux e no macOS. Veja Base64 com OpenSSL. python3 -m base64 -d fileepython3 -m base64 filefuncionam onde o coreutils não está disponível; a saída quebra em 76 caracteres.- No Kubernetes, o padrão é
kubectl get secret x -o jsonpath='{.data.password}' | base64 -d, ou use o decodificador de secrets do Kubernetes.
Perguntas frequentes
Por que echo hello | base64 dá um resultado diferente das ferramentas online?
O echo acrescenta uma quebra de linha, então você codifica hello\n (aGVsbG8K) em vez de hello (aGVsbG8=). Use printf '%s' hello ou echo -n hello.
Como impedir que o base64 quebre as linhas?
No Linux, base64 -w 0. O macOS não quebra por padrão. Para um comando que se comporte igual nos dois, passe a saída por tr -d '\n'.
O que significa 'base64: invalid input'?
O base64 -d do GNU encontrou um caractere fora do alfabeto ou um preenchimento quebrado. Ele imprime os bytes que decodificou até ali, depois o erro, e sai com status 1. Os culpados comuns são - e _ do URL-safe, aspas e prefixos data:.
O base64 -d no macOS é igual ao do Linux?
Versões antigas do macOS só conheciam -D (ou --decode); as recentes também aceitam -d. Use --decode em scripts que precisam rodar nos dois.