45

If you run this command on your Unix

echo -n "foo" | openssl dgst -sha1

You will get this output:

(stdin)= 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33

(followed by a newline).

How can I force openssl to not show the (stdin)= prefix, and avoid the trailing newline?

Kevdog777
  • 3,194
  • 18
  • 43
  • 64
  • @MarkDavidson Hmm, interesting. Are you sure it doesn't even append a newline? –  Jul 10 '12 at 18:41

4 Answers4

38

Raw binary format does not add any extraneous output.
Output as binary then convert to hex:

echo -n "foo" | openssl dgst -sha1 -binary | xxd -p

Will give you this:

0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33

This method should be future-proof in case someone decides to change the textual output format again. I'm sure they will fix the prefix to be "SHA1(stdin)= " to be consistent with that of a file input.

I can't believe that they changed this! I wonder how many scripts were broken.

Evil Hacker
  • 481
  • 4
  • 3
  • 14
    It will only output 20-30 octets per line (or 40-60 characters). For SHA-256 checksum, this is not enough sometimes. Use the `-c 256` option to extend it to 256 octets per line. – Rockallite Jan 17 '17 at 09:02
  • Nice solution but do you have any idea what's the usage of that prefix? – Amir Karimi Mar 02 '20 at 17:47
17

I observe this behavior under OpenSSL 1.0.0e on Ubuntu 11.10, whereas OpenSSL 0.9.8k and 0.9.8t output just the hash. OpenSSL's command line is not designed to be flexible, it's more of a quick-and-dirty way to perform cryptographic calculations from the command line.

If you want to use OpenSSL, filter the output:

echo -n "foo" | openssl dgst -sha1 | sed 's/^.* //'

On Linux (with GNU tools or BusyBox), you can use sha1sum, which doesn't require OpenSSL to be installed and has a stable output format. It always prints a file name, so strip that off.

echo -n "foo" | sha1sum | sed 's/ .*//'

On BSD systems including OSX, you can use sha1.

echo -n "foo" | sha1 -q

All of these output the checksum in hexadecimal followed by a newline. Text under unix systems always consists of a sequence of lines, and each line ends with a newline character. If you store the output of the command in a shell variable, the final newline is stripped off.

digest=$(echo -n "foo" | openssl dgst -sha1 | sed 's/^.* //')

If you need to pipe the input into a program that requires a checksum with no final newline (which is really rare), strip off the newline.

echo -n "foo" | openssl dgst -sha1 | sed 's/^.* //' | tr -d '\n' | unusual_program
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
8

Here's another alternative:

echo -n "foo" | openssl sha1 | awk '{print $2}'
Michael Mrozek
  • 91,316
  • 38
  • 238
  • 232
Vishnu Kumar
  • 262
  • 4
  • 11
  • 1
    I know the question asks with this specific format, however, if someone tries to extend this to include filenames, it could break if the filename has spaces in it. Just a heads up for other people who land here. – Cameron Gagnon Sep 22 '16 at 03:38
  • A slight change to this will resolve that issue: `echo -n "foo" | openssl sha1 | awk '{ print $NF }'` . This will also work with the openssl that comes with macOS (LibreSSL). – internetdotcom Jan 19 '21 at 02:05
  • @dpk That will not resolve the space issue still – Vishnu Kumar Jan 19 '21 at 09:32
3

Here's a way to do it using bash built-ins instead of pipes, awk, sed, tr, cut, etc:

output="$(openssl sha1 <(printf foo))"; echo ${output/* }
al-x
  • 131
  • 1