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

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##*.}"

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.


  • 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:

    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.


md5name () {
    local base=${1##*/}
    local ext=${base##*.}
    local dir=${1%/*}

    printf '%s' "${base%.$ext}" | md5sum |
    awk -v dir="$dir" -v ext="$ext" '{ printf("%s/%s.%s\n", dir, $1, ext) }'

dir=$HOME  # where your files are

for pathname in "$dir"/*; do
    test -f "$pathname" || continue
    echo mv "$pathname" "$( md5name "$pathname" )"

This bash script uses the md5sum utility from GNU coreutils to compute the MD5 hash from the base name (sans extension) of any given pathname. The helper function md5name does the actual computation and will output the new name with complete path and extension.

The md5name function uses awk to assemble the new name from the parts of the given pathname and the result from md5sum.

Examples of the function in use by itself:

$ md5name '/some/path/file name here.extension'

... where c9e89fa443d16da4b96ea858881320c9 is the MD5 hash of the string file name here.

Remove the echo from the script at the top to actually rename the files. You may want to save the output of the original script to file (with the echo in place) if you at some point need to restore the file names to their originals.

Note that running this twice on a set of files will compute the MD5 hash of MD5 hashes, and that the original filename then becomes unrecoverable unless you make careful notes about what files are called what after each run of the script.

With perl's rename:

find . -name '*.jpg' -type f -exec rename -n '
  BEGIN{use Digest::MD5 qw(md5_hex)}
  my ($dir, $name, $ext) = m{(.*)/(.*)\.(.*)}s;
  $_ = "$dir/" . md5_hex($name) . ".$ext"' {} +

(remove -n when happy).