This in approach I often like using.
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \\`echo \1 \| md5sum \| cut -d' ' -f 1\\`.\2|" | sh -
The "ls" command produces a stream of text lines.
The "sed" command tranforms each line with pattern-matching rules.
The "sed" command outputs a "mv" command which is then piped though a shell "sh" for execution.
The "mv" command's parameters are like "mv oldfilename newfilename", which renames the file.
I construct the new file-name with a sed command that takes the part before the last dot, and echoes it into the input of the "md5sum" command, and then takes just the hash from it's output.
Walking through my process, first list files ('head -n 3' to just see the first 3 lines):
ls | head -n 3
1000-26092016.xml
1000-27092016.xml
12312-28092016.xml
Then think about transforming with sed (not yet piping any generated commands through a shell)
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \1.\2|" | head -n 3
mv 1000-26092016.xml 1000-26092016.xml
mv 1000-27092016.xml 1000-27092016.xml
mv 12312-28092016.xml 12312-28092016.xml
There are three match patterns:
^\(.*\) = match from start-of-line up to a dot
\. = matches a single dot
\([^\.]*\)$ = match 0-or-more non-dot chars from end of line
I want to use sed to replace an input filename with "mv filename NEWfilename",
but as I'm piping commands through a shell, I can generate commands that get the md5sum, like this
echo "1000-26092016" | md5sum
55b18a6b0add4a318b0079e18512b4e8 -
to get just the hash
echo "1000-26092016" | md5sum | cut -d' ' -f 1
55b18a6b0add4a318b0079e18512b4e8
In a unix shell, we can use backtick operators (`some_command`) to run a sub-command, so for example
echo "howdy date there"
howdy date there
echo "howdy `date` there"
howdy Fri Sep 15 18:39:00 IST 2017 there
Back to the mv command, I want sed to produce "mv here there" with "there" replaced with a backtick command to get the md5sum.
The string inside the sed replace-string starts like this
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 `echo \1 | md5sum | cut -d' ' -f 1`.\2|" | head -n 3
mv 1000-26092016.xml b026324c6904b2a9cb4b88d6d61c81d1.xml
mv 1000-27092016.xml b026324c6904b2a9cb4b88d6d61c81d1.xml
mv 12312-28092016.xml b026324c6904b2a9cb4b88d6d61c81d1.xml
But is clearly making the same hash for each filename, as the backticked-command is being run before sed sees the string.
To stop the shell running the backtick command so sed will output the backticks, we have to prepend slashes (also to the pipe-character), so again:
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2|" | head -n 3
mv 1000-26092016.xml `echo 1000-26092016 | md5sum | cut -d' ' -f 1`.xml
mv 1000-27092016.xml `echo 1000-27092016 | md5sum | cut -d' ' -f 1`.xml
mv 12312-28092016.xml `echo 12312-28092016 | md5sum | cut -d' ' -f 1`.xml
The output also needs filenames to be quoted in case of spaces, so
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | grep trick
mv "a trick€€ fíle nÁme.xml" "`echo a trick€€ fíle nÁme | md5sum | cut -d' ' -f 1`.xml"
So lets try this one out, by piping it through a shell:
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | grep trick | sh -
Did it work ? i guess:
echo "a trick€€ fíle nÁme" | md5sum
629db9c3071928ba0746f18444713b65 -
ls 629db9c3071928ba0746f18444713b65*
629db9c3071928ba0746f18444713b65.xml
Here's an approach to cross-check; use "ls" option "-i" to output the unix filesystem i-node (which doesn't change with "mv"):
ls -1i | sort -n > .before
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | sh -
ls -1i | sort -n > .after
cut -d' ' -f 1 .before | while read I ; do echo "mv'd \"`grep ${I} .before`\" to \"`grep ${I} .after`\"" | sed "s| *$I *||g" ; done | head -n 3
mv'd "1000-26092016.xml" to "55b18a6b0add4a318b0079e18512b4e8.xml"
mv'd "1000-27092016.xml" to "b1baa80d99d5edf85c8aeb98185dd440.xml"
mv'd "12312-28092016.xml" to "2b2d692bd047b64c99f7b9161349d430.xml"
Or, using the "paste" command ('coreutils' package)
paste .before .after | head -n 3
36703389 1000-26092016.xml 36703389 55b18a6b0add4a318b0079e18512b4e8.xml
36703390 1000-27092016.xml 36703390 b1baa80d99d5edf85c8aeb98185dd440.xml
36703391 12312-28092016.xml 36703391 2b2d692bd047b64c99f7b9161349d430.xml
fba8255e8e9ce687522455f3e1561e53
is the MD5 hash formynicepicture
, does that mean that the extension should be removed before hashing?md5sum <<<"file name"
thefile name
file existing or not, because it considering as a string except feeding it with existing files name.