5

I would like to rename some files to their contents' MD5 sum; for example, if file foo is empty, it should be renamed to d41d8cd98f00b204e9800998ecf8427e.

Does it have to be script or can I use something like the rename tool?

7
  • Can you show us the output of md5sum /dev/null? Md5sum's output format varies depending on the OS. Sep 17 '15 at 20:51
  • d41d8cd98f00b204e9800998ecf8427e /dev/null
    – Igor V.
    Sep 17 '15 at 21:05
  • Do you want to rename only files in the current dir or recursively rename all files ? Sep 17 '15 at 21:06
  • @don_crissti Depends.
    – Igor V.
    Sep 17 '15 at 21:07
  • 1
    :) in that case the answer to your question is: Depends. Sep 17 '15 at 21:08
8

Glenn's answer is good; here's a refinement for multiple files:

md5sum file1 file2 file3 | # or *.txt, or whatever
    while read -r sum filename; do
        mv -v "$filename" "$sum"
    done

If you're generating files with find or similar, you can replace the md5sum invocation with something like find . <options> -print0 | xargs -0 md5sum (with the output also piped into the shell loop).

This is taking the output of md5sum, which consists of multiple lines with a sum and then the file it corresponds to, and piping it into a shell loop which reads each line and issues a mv command that renames the file from the original name to the sum. Any files with identical sums will be overwritten; however, barring unusual circumstances (like if you're playing around with md5 hash collisions), that will mean they had the same contents, so you don't lose any data anyway. If you need to introduce other operations on each file, you can put them in the loop, referring to the variables $filename and $sum, which contain the original filename and the MD5 sum respectively.

8
  • 1
    Poor habits, instilled by a long history of using sane filenames. Edited.
    – Tom Hunt
    Sep 17 '15 at 20:47
  • I appreciate your answer, but explaining elements of these few lines would help me in manipulating with it and using in similar purposes. Also, right now, when your file1 file2 file3 is replaced with *, it outputs mv: target ‘ba3a926dc70c9bfee424895e278bb6d6’ is not a directory, which makes no sense to me at this moment, since I don't know what I am looking at.
    – Igor V.
    Sep 17 '15 at 20:57
  • Sounds like something is wrong due to characters in the filenames. If you add echo "$filename"; echo "$sum" before the mv line, it will print the specific data that are causing the problem.
    – Tom Hunt
    Sep 17 '15 at 21:08
  • 1
    Instead of piping to xargs -0, you can just use find ... -exec md5sum {} +. Usually you only need xargs if you want to do some processing between find and xargs. Also, read -ra would avoid munging backslashes in filenames. Nice solution though: this should be faster than the obvious solution of running md5sum separately for every file. Sep 18 '15 at 2:02
  • 1
    @PeterCordes True on find -exec ... +; that may be slightly faster than xargs, though only slightly. I'm already using read -r; -a would wordsplit the entire line, rather than just the first two words, and so mess up filenames with spaces in them.
    – Tom Hunt
    Sep 18 '15 at 15:10
4

With zsh:

autoload zmv # best in ~/.zshrc
zmv '**/*(#qD.)' '$(md5sum<$f)'

Would rename all the regular files, recursively.

(note that it will refuse to rename any file if two files in the same directory have the same checksum, add -f to override that).

**/*(#qD.) is zsh's recursive glob with glob qualifiers (in their explicit form as (#q<qualifiers>), D to include hidden files, . to only select regular files.

4
  • Not sure if relevant, since question's tags include bash....
    – Tom Hunt
    Sep 17 '15 at 20:40
  • 3
    With bash, you can wrap that in zsh -c '...'. Generally here, solutions with alternative tools are welcome as the Q&A can be useful to people with different constraints. We also see a lot of persons using the bash tag because they don't know other shells exist. Sep 17 '15 at 20:41
  • Fair enough. And that is an impressive bit of syntax.
    – Tom Hunt
    Sep 17 '15 at 20:42
  • @TomHunt Evidently the intent of the question was to script the task using a commonly available tool, it was not specifically about bash (and so I retagged it accordingly). It would be different if the question was actually about bash. Sep 18 '15 at 0:10
3

bash:

md5sum my.file.here | { read sum filename; mv $filename $sum; }
1
  • How to use command for multiple files?
    – Igor V.
    Sep 17 '15 at 20:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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