221
$ echo -n "apfjxkic-omyuobwd339805ak:60a06cd2ddfad610b9490d359d605407" | base64
YXBmanhraWMtb215dW9id2QzMzk4MDVhazo2MGEwNmNkMmRkZmFkNjEwYjk0OTBkMzU5ZDYwNTQw
Nw==

The output has a return before Nw==. What is the correct way to generate base64 in Linux?

terminal screenshot

13
  • 6
    Are you certain the output contains a newline, and it's not just your window wrapping? That command worked fine for me on mac. What OS are you using?
    – Ian
    Commented Jul 3, 2017 at 5:10
  • 56
    RFC 2045, which defined Base64, REQUIRES a newline after 76 characters (max). What makes you think your example is not the correct way?
    – MSalters
    Commented Jul 3, 2017 at 8:40
  • 37
    @MSalters RFC 4648 specifically addresses that issue. Implementations MUST NOT add line feeds to base-encoded data unless the specification referring to this document explicitly directs base encoders to add line feeds after a specific number of characters. => this implementation is incorrect according to RFC 4648, as long as it claims to produce 'plain' base64-encoded output. More interestingly, GNU base64 (in question?) manpages specifically refers to RFC 3548, which also specifies no wrapping by default, and which RFC 4648 obsoletes.
    – Bob
    Commented Jul 3, 2017 at 10:46
  • 4
    @Bob: RFC's have a bit less respect for API stability; a base64 tool can't just change its output format without breaking scripts.
    – MSalters
    Commented Jul 4, 2017 at 6:44
  • 3
    @MSalters I cannot be certain an older version does not exist, but GNU base64 was written in 2004 and AFAICT always claimed to follow RFC 3548. RFC 3548 contains the same "MUST NOT add line feeds" clause. So even the original implementation was "wrong". At the very least, its implementation does not match its documentation. Anyway, you asked for why OP's example is correct and referenced an RFC; my response is the correct RFC that actually defines base64 in isolation. If your answer is "for historical reasons", so be it, but OP isn't wrong here.
    – Bob
    Commented Jul 4, 2017 at 7:05

4 Answers 4

364

Try:

echo -n "apfjxkic-omyuobwd339805ak:60a06cd2ddfad610b9490d359d605407" | base64 -w 0

From man base64:

-w, --wrap=COLS
Wrap encoded lines after COLS character (default 76). Use 0 to disable line wrapping.

A likely reason for 76 being the default is that Base64 encoding was to provide a way to include binary files in e-mails and Usenet postings which was intended for humans using monitors with 80 characters width. Having a 76-character width as default made that usecase easier.

10
  • 29
    Oh man, I always just piped this through tr. Good to know there's a "proper way". Commented Jul 3, 2017 at 17:05
  • The explanation about why the default value is not zero is a mistery for me.
    – Dherik
    Commented Jul 25, 2019 at 21:01
  • 4
    @Dherik I guess it's courtesy towards text processing tools. base64 encodes arbitrary binary data as text. Tools that expect text usually read one line at a time and may not deal with very long lines well. If -w 0 was the default, you would get by default just one line of text; an enormously long line if the input was large. It's better to wrap by default. I think 76 was chosen because it's little less than 80 which is a sort of de-facto standard for terminals. Commented Jul 25, 2019 at 21:32
  • @KamilMaciorowski thank you for the information. Every time that I used the base64 command I needed to pass the -w 0 (and when I forgot, weird things can happen...), so this default behaviour was very strange to me.
    – Dherik
    Commented Jul 25, 2019 at 21:35
  • 3
    @Dherik A likely reason is that base64 encoding was to provide a way to include binary files in emails and usenet postings which was intended for humans using monitors with 80 characters width. Having a 76-character width as default made that usecase easier. Commented Jan 20, 2020 at 6:19
85

On systems where the -w option to base64 is not available (e.g. Alpine Linux, an Arch Linux initramfs hook, etc.), you can manually process the output of base64:

base64 some_file.txt | tr -d \\n

This is the brute-force approach; instead of getting the program to co-operate, I am using tr to indiscriminately strip every newline on stdout.

3
  • 3
    Always use the hammer when available.
    – dna
    Commented Sep 16, 2020 at 11:56
  • 2
    The following was useful for "correcting" a base64-encoded value: echo 'dGVzdAo=' | base64 -d | tr -d \\n | base64 Commented Mar 16, 2021 at 0:32
  • Not inferior, just a different and often only approach. As you said there are plenty of systems out there without the -w option, including MacOSX..
    – nnsense
    Commented Nov 1, 2021 at 20:05
6

So please use echo -n to remove the line break before redirecting to base64; and use base64 -w 0 to prevent base64 itself to add line break into the output.

me@host:~ 
$ echo -n mypassword | base64 -w 0
bXlwYXNzd29yZA==me@host:~ # <<<<<<<<<<<<<<< notice that no line break added after "==" due to '-w 0'; so me@host is on the same line
$ echo -n 'mypassword' | base64 -w 0
bXlwYXNzd29yZA==me@host:~ # <<<<<<<<<<<<<<<<<< notice adding single quotes does not affect output, so you can use values containing spaces freely

A good way to verify is using od -c to show the actual chars.

me@host:~ 
$ echo -n bXlwYXNzd29yZA== | base64 -d | od -c
0000000   m   y   p   a   s   s   w   o   r   d
0000012

You see no "\n" is added. But if you use "echo" without "-n", od will show "\n":

me@host:~ 
$ echo mypassword | base64 -w 0
bXlwYXNzd29yZAo=me@host:~ 
$ echo bXlwYXNzd29yZAo= | base64 -d | od -c
0000000   m   y   p   a   s   s   w   o   r   d  \n
0000013

At last, create a function will help you in the future:

base64-encode() {
    if [ -z "$@" ]; then
        echo "Encode string with base64; echoing without line break, and base64 does not print line break neither, to not introducing extra chars while redirecting. Provide the string to encode. "
        return 1
    fi
    echo -n "$@" | base64 -w 0  # here I suppose string if containing space is already quoted
}
5

For anyone using openssl base64, you can use the -A flag:

 -A                 Process base64 data on one line (requires -a)
 -a                 Perform base64 encoding/decoding (alias -base64)

The following worked for me:

echo -n '{string}' | openssl base64 -A

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .