Here is a short command that does most of what you asked for:
Code:
find ! -name @md5sum.md5 -type d -execdir /bin/bash -c 'cd "$0"; md5sum * > @md5sum.md5' {} \;
Edit: Um, I guess since we have -type d
we don't need ! -name @md5sum.md5
, so this should work the same...
Code:
find -type d -execdir /bin/bash -c 'cd "$0"; md5sum * > @md5sum.md5' {} \;
It is not quite perfect, for at least two reasons: (1) md5sum gives an error message when its argument includes a directory, and (2) if there are no regular files in the directory, md5sum runs anyway and creates an empty .md5 file
, and (3) it doesn't exclude @md5sum.md5. But it does handle unusual filenames. I tested it with filenames containing spaces and newline characters, and it worked fine, so I think it should work for filenames containing any special characters.
Just for fun and for learning, I tried a true recursive method. As a wise person once said:
Quote:
"If you want to do something recursively, try recursion."
|
At first, I had no idea how to do it, but I googled around and tried some methods to see where they failed, and repeated that process until it worked the way I wanted.
It works better than the short command above, in that it does not pass directory names to md5sum, so we avoid those pesky error messages, and it does not run md5sum on empty directories, so there are no zero-length .md5 files,
and it correctly excludes @md5sum.md5.
Yes, I know recursion can use up a lot of resources, in this case creating subshells within subshells, but at least it can be an interesting and fun programming exercise. Here's what I got:
Code:
#!/bin/bash
md5sum_recursive() {
find -maxdepth 1 -mindepth 1 \! -name "@md5sum.md5" -type f -execdir /bin/bash -c 'md5sum "$0" >> "@md5sum.md5"' {} \; -o -type d -execdir /bin/bash -c 'cd "$0"; md5sum_recursive' {} \;
}
export -f md5sum_recursive
md5sum_recursive
In this script, we define a function that calls itself.
It does that when it finds a directory and needs to descend one level into it.
When it finds a regular file, it executes md5sum on it.
-maxdepth 1 restricts the find command to the current directory only. In effect, this takes all the recursion out of the find command, so we have to set up the recursion ourselves.
-mindepth 1 prevents the find command from finding the current directory, which would lead to an infinite recursion.
\! -name "@md5sum.md5" excludes the md5sum report files.
Problem: If @md5sum.md5 already exists, lines will be appended to it, probably leading to much duplication.
-execdir /bin/bash is necessary because we need a shell in order to define and use a shell function. It may be possible to implement the same logic by a recursive shell script rather than a recursive shell function, but I haven't tried that.
The
'... "$0" ...' {} arrangement (the use of "$0" inside the single quotes, with the brace pair outside of the single quotes) is necessary in order to handle filenames with special characters.