264

I use md5sum to generate a hash value for a file. But I only need to receive the hash value, not the file name.

md5=`md5sum ${my_iso_file}`
echo ${md5}

Output:

3abb17b66815bc7946cefe727737d295  ./iso/somefile.iso

How can I 'strip' the file name and only retain the value?

4
  • 68
    Very surprising this isn't an option for md5sum. Commented Jan 10, 2017 at 4:39
  • 21
    Agreed! Why isn't this an option? Can a GNU-Master shed some light?
    – rinogo
    Commented Jul 28, 2017 at 0:46
  • 1
    Why do you need to have a "only hash" flag when you can trim the result with some regex? (I am sarcastic) Commented Apr 21, 2020 at 21:53
  • Seems like someone should either open a PR or a bug report to enhance this... I'm having a weird realization that although this stuff is all open source, I don't actually have any idea how I'd contribute to it if I wanted to. Commented Jun 18 at 15:26

17 Answers 17

259

A simple array assignment works... Note that the first element of a Bash array can be addressed by just the name without the [0] index, i.e., $md5 contains only the 32 characters of md5sum.

md5=($(md5sum file))
echo $md5
# 53c8fdfcbb60cf8e1a1ee90601cc8fe2
10
  • 2
    the first line doesn't work inside the do section of a for loop...as a Bash newb I don't yet know why
    – Andy
    Commented Jul 29, 2015 at 1:20
  • 1
    @Andy: If you try this line of code (in the terminal, or in a script): echo>file; for i in file; do md5=($(md5sum file)); echo $md5; done - It should output 68b329da9893e34099c7d8ad5cb9c940
    – Peter.O
    Commented Jul 29, 2015 at 8:35
  • 1
    How come echo ($(echo -n foo | md5sum)) doesn't work? Errors out bash: syntax error near unexpected token $(echo -n foo | md5sum)'
    – lkraav
    Commented Aug 26, 2015 at 4:42
  • 3
    @lkraav: The command echo -n foo | md5sum outputs 2 shell words to stdout: acbd18db4cc2f85cedef654fccc4a4d8 and - (the - indicates the source as stdin). – You must tell bash to capture those words into a string, using Command Substitution: $( command ). – The ( brackets ) produce a bash array with 2 elements. However, you must assign that array construct ( … ) to an variable name; hence, using md5 as the array name: md5=($(echo -n foo | md5sum)). You haven't assigned the array to a variable name
    – Peter.O
    Commented Aug 26, 2015 at 7:04
  • 4
    This is a bash question, but note that this doesn't work in zsh. Instead you can echo $md5[1] to get only the hash (but this isn't portable to bash)...
    – Shane
    Commented Mar 8, 2016 at 9:04
229

Using AWK:

md5=`md5sum ${my_iso_file} | awk '{ print $1 }'`
2
  • Wrong it gives following output on Mac MD5 (/Users/hello.txt) = 24811012be8faa36c8f487bbaaadeb71 and your code returns MD5.
    – alper
    Commented Aug 3, 2018 at 21:06
  • You can get run of - by adding | awk '{print $1}' end of your code => md5sum < ${my_iso_file} | awk '{print $1}' @ChristopheDeTroyer
    – alper
    Commented Aug 3, 2018 at 21:11
87

You can use cut to split the line on spaces and return only the first such field:

md5=$(md5sum "$my_iso_file" | cut -d ' ' -f 1)
1
  • 7
    @CzarekTomczak True, but just by using this answer's method, you could reuse it with different hashing algorithms just by changing the command itself. md5sum -> sha256sum without remembering what amount of characters you need to "cut". Commented Aug 15, 2018 at 1:05
33

On Mac OS X:

md5 -q file
4
  • 1
    doesn't work on my Mac OS X 10.7. But thanks for posting, for whatever version this works on. Commented Jan 10, 2017 at 4:38
  • Also gmd5sum from coreutils would work on MacOS like md5sum in other answers mentioned here. Commented Nov 21, 2018 at 16:00
  • It worked for me on version 11.5.2 but after removing the -q option Commented Sep 15, 2021 at 14:01
  • md5 is different from md5sum, which is what OP asked about. Commented Sep 27, 2021 at 21:19
17
md5="$(md5sum "${my_iso_file}")"
md5="${md5%% *}" # remove the first space and everything after it
echo "${md5}"
2
  • Nice. One note -- on the first line you don't need quotes around $() (although they do no harm) but certainly need them around ${}. Commented Sep 13, 2010 at 20:26
  • 2
    @Roman: yeah, I tend to habitually quote any expansion (unless there's a reason not to) -- it's easier than keeping track of the cases where it's safe to skip the quotes. (Although in this case, I left them off the actual filename... stand by for an edit.) Commented Sep 14, 2010 at 6:31
14

Another way is to do:

md5sum filename | cut -f 1 -d " "

cut will split the line to each space and return only the first field.

0
11

By leaning on head:

md5_for_file=`md5sum ${my_iso_file}|head -c 32`
7

If you need to print it and don't need a newline, you can use:

printf $(md5sum filename)
6

One way:

set -- $(md5sum $file)
md5=$1

Another way:

md5=$(md5sum $file | while read sum file; do echo $sum; done)

Another way:

md5=$(set -- $(md5sum $file); echo $1)

(Do not try that with backticks unless you're very brave and very good with backslashes.)

The advantage of these solutions over other solutions is that they only invoke md5sum and the shell, rather than other programs such as awk or sed. Whether that actually matters is then a separate question; you'd probably be hard pressed to notice the difference.

1
  • The question is tagged with Bash, but perhaps indicate how much of this is Bash-specific (e.g., would it work in Z shell (now allegedly the default shell in macOS v10.15 (Catalina) and later)). Commented Apr 19, 2021 at 15:46
3
md5=$(md5sum < $file | tr -d ' -')
2
md5=`md5sum ${my_iso_file} | cut -b-32`
1

md5sum puts a backslash before the hash if there is a backslash in the file name. The first 32 characters or anything before the first space may not be a proper hash.

It will not happen when using standard input (file name will be just -), so pixelbeat's answer will work, but many others will require adding something like | tail -c 32.

1

if you're concerned about screwy filenames :

md5sum < "${file_name}" | awk NF=1   
f244e67ca3e71fff91cdf9b8bd3aa7a5

other messier ways to deal with this :

md5sum "${file_name}" | awk NF=NF OFS= FS=' .*$' 
                     or
                      | awk '_{ exit }++_' RS=' '    
f244e67ca3e71fff91cdf9b8bd3aa7a5

to do it entirely inside awk :

mawk 'BEGIN {
    __ = ARGV[ --ARGC ]
     _ = sprintf("%c",(_+=(_^=_<_)+_)^_+_*++_) 
    RS = FS
    gsub(_,"&\\\\&",__)

    ( _=" md5sum < "((_)(__)_) ) | getline

    print $(_*close(_)) }' "${file_name}"
f244e67ca3e71fff91cdf9b8bd3aa7a5
0

Well, I had the same problem today, but I was trying to get the file MD5 hash when running the find command.

I got the most voted question and wrapped it in a function called md5 to run in the find command. The mission for me was to calculate the hash for all files in a folder and output it as hash:filename.

md5() { md5sum $1 | awk '{ printf "%s",$1 }'; }
export -f md5
find -type f -exec bash -c 'md5 "$0"' {} \; -exec echo -n ':' \; -print

So, I'd got some pieces from here and also from 'find -exec' a shell function in Linux

0

For the sake of completeness, a way with sed using a regular expression and a capture group:

md5=$(md5sum "${my_iso_file}" | sed -r 's:\\*([^ ]*).*:\1:')

The regular expression is capturing everything in a group until a space is reached. To get a capture group working, you need to capture everything in sed.

(More about sed and capture groups here: How can I output only captured groups with sed?)

As delimiter in sed, I use colons because they are not valid in file paths and I don't have to escape the slashes in the filepath.

1
  • 1
    Why capture? You can simply delete the space and what is behind: sed 's: .*::' does the same thing!
    – MoonCactus
    Commented Oct 20, 2020 at 7:18
-2
md5=$(md5sum < index.html | head -c -4)
1
  • Strange that this was downvoted. I prefer the other answer using head - the first 32 characters. But still... Commented Nov 23, 2023 at 11:47
-3

Another way:

md5=$(md5sum ${my_iso_file} | sed '/ .*//' )
1
  • missing a character: sed 's/ .*//'
    – Dino Dini
    Commented Sep 2, 2022 at 0:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.