Annnnnd I’m done.
Did I say “done?” Now using a regex that will (should) only pick viable dates, although other strings can match. Notably a time string that meets the [01-12].[01-31].[00-99] format. Also added some error checking… or at least that’s the idea. Unsure if working at this time. I don’t believe it do. Only if `date` can’t reformat the string it’s fed will it be able to notice, but that is printed to stdout already. It’s the “Warning:” lines that are ambiguous.
Removed the “error checking” which didn’t work. I suggest making note of any errors reported to stdout while the script runs.
The main extended regex that matches the mm.dd.(yy)yy pattern is now a variable.
#!/bin/sh
# http://strawhousepig.net/
# The following `egrep` (or `grep -E`) should prove useful when checking the
# storage file. If your text editor supports grep based 'find all' you
# may be able to highlight the original text that is to be changed.
# egrep -nv '(1[0-2]|0?[1-9])[.-/,]([0-2]?[1-9]|[1-3][0-1])[.-/,](20)?[0-9]{2}(\.[[:alnum:]]+)?[[:space:]]/'
# Name of file in which to store 'mv' statements.
mvstore="mvstore.sh"
# The number of parentheses here affects the `sed` for $e. Currently "\4".
dateregex="(1[0-2]|0?[1-9])[.-/,]([0-2]?[1-9]|[1-3][0-1])[.-/,](20)?[0-9]{2}"
usage="
This script looks recursively for the date pattern mm.dd.yy and similar
in file and directory names beginning at 'pwd'. It then generates an 'mv'
statement for each item with the pattern re-written by 'sed' & 'date'
to yyyy-mm-dd.
Running the '-e' option without first creating and checking the storage
file is not recommended.
-w Write the 'mv' statements to the file '$mvstore'
in the present working directory.
-e Evaluate the 'mv' statements as they are generated.
-h Displays this helpful text.
\n"
function mvdatef() {
# Here, 'tail' reverses the order of 'find' after 'egrep' filters the result.
# That way files in a directory are renamed before the directory is.
# 'find' might be able to use the regex, but I couldn't work it out. YMMV.
# This only looks for the pattern at the end of the line or just before an extension.
# If something isn't working, the regex here is probably where it started.
find "`pwd`" | egrep '[/[:space:]]'"$dateregex"'(\.[[:alnum:]]+)?$' | tail -r | while read a
do
# Escape certain characters so they don't wreck the 'mv' statement later.
# double quote, single quote, parens, ampersand, dollar sign, and space.
# Single quote, parens, and ampersand are escaped for the shell after breaking out of the 'sed' statement.
b=$(echo "$a" | sed -E 's/(["'\'\(\)\&'[:space:]$])/\\\1/g')
if [ "$b" == "" ]; then
echo "Error: Could not escape $a" >> $mvstore
fi
# Suck out the last instance of our hated date pattern (00.00.00 or 00.00.0000).
# Also replace dashes, slashes (not working :| ), and errant commas for dots
# because we've come too far not to.
c=$(echo "$a" | egrep -o "$dateregex" | tail -1 | sed -E 's/[-/,]/\./g')
if [ "$c" != "" ]; then
# 'date' will not accept a 2 OR 4 digit year.
if [ $(echo $c | egrep -o "[0-9]{4}$") ]; then
dform="%m.%d.%Y"; else
dform="%m.%d.%y"
fi
d="$(date -j -f "$dform" "$c" "+%Y-%m-%d")"
if [ "$d" == "" ]; then
echo "Error: Could not format date from $c" >> $mvstore
fi
# This is the 'sed' that finds the date and replaces it with what we made just above.
# It looks for the pattern at the end of the line (path) but includes the extension if there.
# It is possible that a version number of some sort will also match.
# Also possible to do away with the EOL in the regex and just go for the pattern.
e="$(echo "$b" | sed -E 's/'"$dateregex"'(\.[[:alnum:]]+)?$/'$d'\4/')"
if [ "$e" == "" ]; then
echo "Error: Could not replace $c in $a" >> $mvstore
fi
# After all that dicking around, this is the mv statement.
f="mv -- $b $e"
if [ $1 ]; then
eval $f
else
echo "$f" >> "$mvstore"
fi
else
echo "Error: $c - Could not pull viable date from $b" >> $mvstore
fi
done
}
if [[ $1 = "-h" ]] ; then
printf "$usage"
exit
elif [[ $1 = "-e" ]]; then
echo "Evaluating 'mv' statements as they are generated..."
mvdatef -e
elif [[ $1 = "-w" ]]; then
echo "Generating file `pwd`/$mvstore and writing 'mv' statements to it..."
printf "#/bin/sh\n# `date`\n" > "$mvstore"
mvdatef
else
printf "$usage"
exit
fi
Original, less-good version: http://strawhousepig.net/shell-script-to-re-format-poor-date-format-in-filenames/