Rename all files in a directory to the md5 hash of their filename (not content)

command linemvrename

I'm very new to linux / command line and need to encrypt the names of 10K+ files (unique names) so they match the MD5 encrypted name in the mySQL database.
I've seen how you can rename a directory of files and how to get the hash of a file (mdsum?) but I'm stuck on how to get the hash of the file name and then rename that file to the generated hash retaining the extension i.e.

mynicepicture.jpg > fba8255e8e9ce687522455f3e1561e53.jpg 

It seems like it should be a simple rename or mv line but I can't get my head around it.
Many thanks for your insights

PS I've seen the use of Perl functions in a few examples close to what I'm looking for but have no idea where / how to use those.

Best Answer

You didn't say which shell you want to use, so I'm just assuming Bash – the answer needs adjustments to work with other shells.

for i in *; do sum=$(echo -n "$i"|md5sum); echo -- "$i" "${sum%% *}.${i##*.}"; done

Script version:

for i in *; do
  sum=$(echo -n "$i" | md5sum)
  echo -- "$i" "${sum%% *}.${i##*.}"
done

This simple for loop takes every file in the current directory, computes the md5 sum of its name and outputs it. Use this to check the functionality, if you want to start renaming replace the second echo by mv.

Explanations

  • echo -n "$i" | md5sum – calculate md5 sum of the full file name including the file extension (Piping), to strip the extension change echo -n "$i" to one of the following:

    ${i%%.*}
    sed 's/\..*//' <<< "$i"
    echo "$i" | sed 's/\..*//'
    
  • sum=$(…) – execute and save the output in $sum (Command Substitution)

  • ${sum%% *} – output everything until the first space (Parameter Substitution), the same as one of the following:

    $(sed 's/ .*//' <<< "$sum")
    $(echo "$sum" | sed 's/ .*//')
    
  • ${i##*.} – output everything after the last dot (Parameter Substitution), the same as one of the following:

    $(sed 's/.*\.//' <<< "$i")
    $(echo "$i" | sed 's/.*\.//')
    

If you need to rename files recursively in different folders, use find with the -exec option.

Related Question