Base64 Encode Linux: Command Line Encoding and Decoding
On Linux the base64 command from GNU coreutils handles both directions. The commands are short; the surprises are all in whitespace, line wrapping and shell quoting. Here is the practical set, with the traps called out.
The four commands you need
Two directions, two kinds of input — files and strings:
# file: encode, then decode back
base64 file.bin > file.b64
base64 -d file.b64 > file.bin
# string: encode, then decode back
printf %s 'my text' | base64
printf %s 'bXkgdGV4dA==' | base64 -d
Use printf %s rather than echo. echo appends a newline, which becomes part of the encoded bytes and produces a different string than every online encoder — the single most common reason a hand-built token does not match.
Line wrapping
By default GNU base64 wraps output at 76 characters, following the MIME convention. That breaks anything expecting a single-line value, such as a Kubernetes secret or an Authorization header.
Disable it with -w 0. On macOS and BSD that flag does not exist, so strip the newlines instead — decoding tolerates wrapped input either way:
# GNU coreutils (Linux)
base64 -w 0 file.bin
# macOS / BSD
base64 -i file.bin | tr -d '\n'
Real-world one-liners
# Basic auth header value
printf %s 'user:pass' | base64 -w 0
# read a Kubernetes secret
kubectl get secret my-secret -o jsonpath='{.data.password}' | base64 -d
# peek at a JWT payload
cut -d. -f2 token.txt | base64 -d 2>/dev/null
# copy an encoded archive to the clipboard
base64 -w 0 archive.tar.gz | xclip -selection clipboard
Send the first result as Authorization: Basic <result>. The JWT line is the one that surprises people: JWTs use base64url without padding, so base64 -d may complain about invalid input — that is expected, and the output printed before the error is still readable.
When decoding fails
"invalid input" almost always means padding or alphabet. Standard Base64 needs a length divisible by 4 with = padding; base64url uses - and _ and often omits padding. Translate the alphabet first, and pass -i to ignore stray whitespace:
# base64url -> standard alphabet, then decode
tr '_-' '/+' < token | base64 -d
# ignore non-alphabet characters (stray whitespace)
base64 -d -i file.b64
Translating the alphabet does not restore the missing =. For the JWT segment eyJzdWIiOiIxIn0, GNU base64 -d prints the full payload, {"sub":"1"}, then base64: invalid input, and exits with status 1. A script that checks $? therefore needs the string padded to a multiple of four first. Also note that -i means --ignore-garbage only in GNU coreutils; on macOS the same letter names the input file.
Frequently asked questions
Why does my command line result differ from an online encoder?
Almost certainly a trailing newline from `echo`. Use `printf %s` and the two will match.
How do I stop base64 from wrapping lines?
Use `base64 -w 0` on Linux, or pipe through `tr -d` on macOS where `-w` is unsupported.
Does base64 -d work with JWT tokens?
Not directly — JWTs use the URL-safe alphabet without padding. Translate - and _ back to + and / and add padding to a multiple of 4 first.