Search code examples
macoshashcommand-lineterminalcommand

How to sha256 each line in a file?


I'm using a macOS Sierra and want to sha256 each line in a file.

File:

test
example
sample

Intended output:

9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08
50D858E0985ECC7F60418AAF0CC5AB587F42C2570A884095A9E8CCACD0F6545C
AF2BDBE1AA9B6EC1E2ADE1D694F41FC71A831D0268E9891562113D8A62ADD1BF

I've found a few ways to do this on Ubuntu, but Mac doesn't seem to have sha256 installed on it. From what is sounds like, you have to use something similar to shasum 256 but nothing seems to be working.


Solution

  • openssl dgst is available out-of-the-box on MacOS (and pretty much everywhere else as well), and can be easily combined with BashFAQ #1 practices for iterating line-by-line:

    ### INEFFICIENT SOLUTION
    hashlines() {
      while IFS= read -r line; do
        printf '%s' "$line" \
          | openssl dgst -sha256 \
          | tr '[[:lower:]]' '[[:upper:]]' \
          | sed -Ee 's/.*=[[:space:]]//'
      done
    }
    

    That said, this is quite wildly inefficient when run on large files. If you need something that performs well, I'd write this in Python instead. Wrapped in the same shell function, with the same calling convention, that might look like:

    ### FAST SOLUTION
    hashlines ()
    {
        python3 -c '
    import sys, hashlib
    for line in sys.stdin:
        print(hashlib.sha256(line.encode().rstrip(b"\n")).hexdigest().upper())'
    }
    

    In either case, usage is just hashlines < filename or hashlines <<< $'line one\nline two'.