Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>whirlpool isn't a very common hash. You'll probably have to install a program to compute it. e.g. Debian/Ubuntu include a "whirlpool" package. The program prints the hash of one file by itself. apt-cache search whirlpool shows that some other packages support it, including the interesting md5deep.</p> <p>Some of the earlier anwsers will fail on filenames with spaces in them. If this is the case, but your files don't have any newlines in the filename, then you can safely use \n as a delimiter.</p> <pre><code> oldifs="$IFS" IFS=" " for i in $(find -type f); do echo "$i";done #output # ./base # ./base2 # ./normal.ext # ./trick.e "xt # ./foo bar.dir ext/trick' (name "- }$foo.ext{}.ext2 IFS="$oldifs" </code></pre> <p>try without setting IFS to see why it matters.</p> <p>I was going to try something with IFS="."; find -print0 | while read -a array, to split on "." characters, but I normally never use array variables. There's no easy way that I see in the man page to insert the hash as the second-last array index, and push down the last element (the file extension, if it had one.) Any time bash array variables look interesting, I know it's time to do what I'm doing in perl instead! See the gotchas for using read: <a href="http://tldp.org/LDP/abs/html/gotchas.html#BADREAD0" rel="nofollow noreferrer">http://tldp.org/LDP/abs/html/gotchas.html#BADREAD0</a></p> <p>I decided to use another technique I like: find -exec sh -c. It's the safest, since you're not parsing filenames.</p> <p>This should do the trick:</p> <pre><code> find -regextype posix-extended -type f -not -regex '.*\.[a-fA-F0-9]{128}.*' \ -execdir bash -c 'for i in "${@#./}";do hash=$(whirlpool "$i"); ext=".${i##*.}"; base="${i%.*}"; [ "$base" = "$i" ] && ext=""; newname="$base.$hash$ext"; echo "ext:$ext $i -> $newname"; false mv --no-clobber "$i" "$newname";done' \ dummy {} + # take out the "false" before the mv, and optionally take out the echo. # false ignores its arguments, so it's there so you can # run this to see what will happen without actually renaming your files. </code></pre> <p>-execdir bash -c 'cmd' dummy {} + has the dummy arg there because the first arg after the command becomes $0 in the shell's positional parameters, not part of "$@" that for loops over. I use execdir instead of exec so I don't have to deal with directory names (or the possibility of exceeding PATH_MAX for nested dirs with long names, when the actual filenames are all short enough.)</p> <p>-not -regex prevents this from being applied twice to the same file. Although whirlpool is an extremely long hash, and mv says File name too long if I run it twice without that check. (on an XFS filesystem.)</p> <p>Files with no extension get basename.hash. I had to check specially to avoid appending a trailing ., or getting the basename as the extension. ${@#./} strips out the leading ./ that find puts in front of every filename, so there is no "." in the whole string for files with no extension.</p> <p>mv --no-clobber may be a GNU extension. If you don't have GNU mv, do something else if you want to avoid deleting existing files (e.g. you run this once, some of the same file are added to the directory with their old names; you run it again.) OTOH, if you want that behaviour, just take it out.</p> <p>My solution should work even when filenames contain a newline (they can, you know!), or any other possible character. It would be faster and easier in perl, but you asked for shell.</p> <p>wallenborn's solution for making one file with all the checksums (instead of renaming the original) is pretty good, but inefficient. Don't run md5sum once per file, run it on as many files at once as will fit on its command line:</p> <p>find dir -type f -print0 | xargs -0 md5sum > dir.md5 or with GNU find, xargs is built in (note the + instead of ';') find dir -type f -exec md5sum {} + > dir.md5</p> <p>if you just use find -print | xargs -d'\n', you will be screwed up by file names with quote marks in them, so be careful. If you don't know what files you might someday run this script on, always try to use print0 or -exec. This is esp. true if filenames are supplied by untrusted users (i.e. could be an attack vector on your server.)</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload