Закодировать и декодировать строку
printf '%s' 'héllo wörld' | base64 # aMOpbGxvIHfDtnJsZA==
printf '%s' 'aMOpbGxvIHfDtnJsZA==' | base64 -d # héllo wörld
base64 кодирует байты, поэтому результат зависит от кодировки терминала. В любой современной Linux или macOS это UTF-8.
Чаще всего подводит echo: он дописывает перевод строки.
echo 'héllo wörld' | base64 # aMOpbGxvIHfDtnJsZAo= (note the "o=")
echo -n hi | base64 # aGk=
echo -n работает в Bash, но не в каждом sh; printf '%s' переносим. Here-string (base64 <<< "text") тоже добавляет перевод строки. Если вам прислали Base64, который заканчивается на Cg== или o=, скорее всего, в конце есть перевод строки. Вставьте строку в декодер Base64 и проверьте.
Флаги GNU (Linux) и BSD (macOS)
| Задача | GNU coreutils (Linux) | macOS |
|---|---|---|
| Декодировать | -d, --decode | -D, --decode (в новых версиях также -d) |
| Без переноса строк | -w 0 | по умолчанию |
| Перенос через N символов | -w N (по умолчанию 76) | -b N |
| Входной файл | base64 file | base64 -i file или base64 < file |
| Выходной файл | перенаправление > | -o file или перенаправление |
| Пропускать мусор при декодировании | -i, --ignore-garbage | нет |
Два флага -i значат разное: в macOS это входной файл, в Linux – пропуск мусора. Переносимые скрипты должны читать из stdin и писать в stdout:
base64 < in.bin | tr -d '\n' > out.b64 # same output on Linux and macOS
base64 --decode < out.b64 > in-copy.bin
GNU base64 по умолчанию переносит строки через 76 символов, а это ломает заголовки и переменные окружения:
head -c 60 /dev/zero | tr '\0' x | base64 -w 0
# eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4
Без -w 0 первая строка будет длиной 76 символов, а остаток уйдёт на вторую. Если вам нужны строки в стиле MIME, перенос по умолчанию вам как раз подходит.
URL-safe Base64
В GNU coreutils 8.31 и новее есть basenc, который поддерживает Base64URL. Дополнение он сохраняет:
printf '%s' '<<???>>' | basenc --base64url # PDw_Pz8-Pg==
printf '%s' 'PDw_Pz8-Pg' | basenc --base64url -d # <<???>>
В macOS или старых Linux замените символы через tr:
printf '%s' '<<???>>' | base64 | tr '+/' '-_' | tr -d '=' # PDw_Pz8-Pg
Для декодирования нужна обратная замена, а строгим декодерам – ещё и возвращённое дополнение:
s=PDw_Pz8-Pg
s=$(printf '%s' "$s" | tr -- '-_' '+/')
while [ $(( ${#s} % 4 )) -ne 0 ]; do s="$s="; done
printf '%s' "$s" | base64 -d # <<???>>
-- не даёт tr принять -_ за опцию. Точно такое же преобразование нужно для JWT; декодер JWT сделает его за вас. Подробнее в статье Base64 и Base64URL.
Кодирование и декодирование файлов
base64 -w 0 hello.txt # aGVsbG8K
base64 -d <<< 'aGVsbG8K' > copy.txt
base64 -d payload.b64 > payload.pdf
base64 читает и пишет блоками, поэтому размер файла не важен. Собрать data URI для картинки можно так:
printf 'data:image/png;base64,%s' "$(base64 -w 0 logo.png)"
Заголовок HTTP Basic Auth:
printf 'Basic %s' "$(printf '%s' 'user:pass' | base64)" # Basic dXNlcjpwYXNz
Генератор заголовка Basic Auth делает то же самое, но ваш пароль не остаётся в истории команд.
Проверка, ошибки и коды выхода
Найдя недопустимый символ, GNU base64 -d завершается с кодом 1 и пишет в stderr base64: invalid input. При этом всё, что успел декодировать, он выводит, и после неудачного декодирования может остаться недописанный файл:
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)
Результаты на coreutils 9.7:
| Вход | Результат |
|---|---|
aGk | hi, код 0 (отсутствие дополнения допускается) |
"aGVs\nbG8K" | hello, код 0 (переводы строк игнорируются) |
aGl= | hi, затем invalid input, код 1 |
a | invalid input, код 1 |
PDw_Pz8-Pg== | часть результата, invalid input, код 1 |
Проверяйте код выхода и декодируйте во временный файл, чтобы ошибка не затёрла нормальные данные:
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
В конвейере $? – это код последней команды. Если base64 -d стоит не последней, добавьте set -o pipefail. Когда строка из лога или письма не декодируется, починка Base64 уберёт кавычки, пробелы и префиксы, а в статье об ошибках разобран каждый случай.
Другие утилиты командной строки
openssl base64есть почти в любой системе и ведёт себя одинаково в Linux и macOS. См. Base64 в OpenSSL.python3 -m base64 -d fileиpython3 -m base64 fileработают там, где нет coreutils; вывод переносится через 76 символов.- В Kubernetes обычно пишут
kubectl get secret x -o jsonpath='{.data.password}' | base64 -d, а можно воспользоваться декодером секретов Kubernetes.
Вопросы и ответы
Почему echo hello | base64 даёт не тот результат, что онлайн-инструменты?
echo добавляет перевод строки, поэтому кодируется hello\n (aGVsbG8K), а не hello (aGVsbG8=). Используйте printf '%s' hello или echo -n hello.
Как запретить base64 переносить строки?
В Linux – base64 -w 0. В macOS строки по умолчанию не переносятся. Чтобы команда вела себя одинаково в обеих системах, пропустите вывод через tr -d '\n'.
Что значит «base64: invalid input»?
GNU base64 -d встретил символ вне алфавита или испорченное дополнение. Он выводит байты, которые успел декодировать, затем ошибку и завершается с кодом 1. Чаще всего виноваты URL-safe символы - и _, кавычки и префиксы data:.
base64 -d в macOS работает так же, как в Linux?
Старые версии macOS знали только -D (или --decode), новые принимают и -d. В скриптах, которые должны работать в обеих системах, пишите --decode.