Only get hash value using md5sum (without filename)
Asked Answered
Z

17

261

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?

Zampardi answered 9/9, 2010 at 18:7 Comment(3)
Very surprising this isn't an option for md5sum.Monovalent
Agreed! Why isn't this an option? Can a GNU-Master shed some light?Pug
Why do you need to have a "only hash" flag when you can trim the result with some regex? (I am sarcastic)Induna
L
227

Using AWK:

md5=`md5sum ${my_iso_file} | awk '{ print $1 }'`
Laticialaticiferous answered 9/9, 2010 at 19:16 Comment(2)
Wrong it gives following output on Mac MD5 (/Users/hello.txt) = 24811012be8faa36c8f487bbaaadeb71 and your code returns MD5.Creeper
You can get run of - by adding | awk '{print $1}' end of your code => md5sum < ${my_iso_file} | awk '{print $1}' @ChristopheDeTroyerCreeper
M
260

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
Microreader answered 24/4, 2011 at 22:47 Comment(10)
Awesome. Just one question, I know the question is tagged bash, but can you tell me if array is a bash only feature or some shell standard?Laticialaticiferous
the first line doesn't work inside the do section of a for loop...as a Bash newb I don't yet know whyDiscovery
@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 68b329da9893e34099c7d8ad5cb9c940Microreader
@Microreader that does, I figured out that the problem was I had #!/bin/sh at the top of my script instead of #!/bin/bash. Thanks!Discovery
How come echo ($(echo -n foo | md5sum)) doesn't work? Errors out bash: syntax error near unexpected token $(echo -n foo | md5sum)'Montes
@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 nameMicroreader
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)...Wedlock
SO: Searching how to create a md5 hash of a file, learning the shortcut access of the first array element. Thanks :)Calvary
To make the script a bit more bulletproof make sure to set IFS explicitly in case it is set to some non-standard value: IFS=" " md5=($(md5sum file))Furtado
This is a nice solution, but it doesn't work in JenkinsCrumhorn
L
227

Using AWK:

md5=`md5sum ${my_iso_file} | awk '{ print $1 }'`
Laticialaticiferous answered 9/9, 2010 at 19:16 Comment(2)
Wrong it gives following output on Mac MD5 (/Users/hello.txt) = 24811012be8faa36c8f487bbaaadeb71 and your code returns MD5.Creeper
You can get run of - by adding | awk '{print $1}' end of your code => md5sum < ${my_iso_file} | awk '{print $1}' @ChristopheDeTroyerCreeper
K
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)
Krawczyk answered 9/9, 2010 at 18:11 Comment(1)
@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".Wideranging
N
32

On Mac OS X:

md5 -q file
Norm answered 10/9, 2010 at 7:56 Comment(4)
doesn't work on my Mac OS X 10.7. But thanks for posting, for whatever version this works on.Monovalent
Also gmd5sum from coreutils would work on MacOS like md5sum in other answers mentioned here.Cumquat
It worked for me on version 11.5.2 but after removing the -q optionLogsdon
md5 is different from md5sum, which is what OP asked about.Messmate
R
17
md5="$(md5sum "${my_iso_file}")"
md5="${md5%% *}" # remove the first space and everything after it
echo "${md5}"
Rom answered 9/9, 2010 at 18:22 Comment(2)
Nice. One note -- on the first line you don't need quotes around $() (although they do no harm) but certainly need them around ${}.Bedridden
@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.)Rom
P
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.

Puttee answered 23/5, 2015 at 9:31 Comment(0)
L
11

By leaning on head:

md5_for_file=`md5sum ${my_iso_file}|head -c 32`
Lotta answered 28/7, 2021 at 11:34 Comment(0)
S
7

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

printf $(md5sum filename)
Samsara answered 15/9, 2016 at 5:16 Comment(0)
C
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.

Chlorothiazide answered 9/9, 2010 at 20:9 Comment(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)).Malti
I
3
md5=$(md5sum < $file | tr -d ' -')
Isotope answered 10/9, 2010 at 15:46 Comment(0)
V
2
md5=`md5sum ${my_iso_file} | cut -b-32`
Veljkov answered 9/9, 2010 at 18:14 Comment(0)
C
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.

Crayon answered 30/12, 2016 at 12:29 Comment(0)
P
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
Pelagia answered 23/8, 2022 at 13:24 Comment(0)
S
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

Satinwood answered 5/1, 2018 at 18:3 Comment(0)
P
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.

Peeling answered 17/5, 2019 at 8:50 Comment(1)
Why capture? You can simply delete the space and what is behind: sed 's: .*::' does the same thing!Khotan
I
-2
md5=$(md5sum < index.html | head -c -4)
Impassion answered 9/9, 2010 at 19:49 Comment(1)
Strange that this was downvoted. I prefer the other answer using head - the first 32 characters. But still...Witchcraft
J
-3

Another way:

md5=$(md5sum ${my_iso_file} | sed '/ .*//' )
Junko answered 9/9, 2010 at 18:23 Comment(1)
missing a character: sed 's/ .*//'Gauche

© 2022 - 2024 — McMap. All rights reserved.