Last active
April 9, 2021 18:48
-
-
Save jamesstout/5930693 to your computer and use it in GitHub Desktop.
rename files to a random filename with 5 digits that contain random numbers and letters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# IRC Issue from helperW | |
# Network: freenode | |
# Channel: #macosx | |
# I have a directory with 001.png 023.png 003.png ( around 800 files) | |
# I have to rename them to a random filename with : 5 digits that contain random numbers and letters | |
# ensure all vars are initialised and exit on error | |
set -o nounset | |
set -e | |
e_header() { | |
printf "\n$(tput setaf 7)%s$(tput sgr0)\n" "$@" | |
} | |
# debug logging | |
e_debug() { | |
printf "$(tput setaf 2)%s$(tput sgr0)\n" "$@" | |
} | |
# Success logging | |
e_success() { | |
printf "$(tput setaf 64)✓ %s$(tput sgr0)\n" "$@" | |
} | |
# Error logging | |
e_error() { | |
printf "$(tput setaf 1)x %s$(tput sgr0)\n" "$@" | |
} | |
# Warning logging | |
e_warning() { | |
printf "$(tput setaf 136)! %s$(tput sgr0)\n" "$@" | |
} | |
# Ask for confirmation before proceeding | |
seek_confirmation() { | |
printf "\n" | |
e_warning "$@" | |
read -p "Continue? (y/n) " -n 1 | |
printf "\n" | |
} | |
# Test whether the result of an 'ask' is a confirmation | |
is_confirmed() { | |
if [[ "$REPLY" =~ ^[Yy]$ ]]; then | |
return 0 | |
fi | |
return 1 | |
} | |
file_exists() { | |
if [ -e "$1" ]; then | |
return 0 | |
fi | |
return 1 | |
} | |
# this is only used to prepare test files | |
prepSampleFiles(){ | |
numFiles=100 | |
# see if first param is really set then check if it is a number | |
if [ -n "$1" ]; then | |
if ! [[ "$1" =~ ^[0-9]+$ ]] ; then | |
e_error "Aborting sample file prep - parameter is not a number" | |
exit 33 | |
else | |
numFiles=$1 | |
fi | |
fi | |
# check if empty - in sub shell so we don't have to reset the shopts | |
files=($(shopt -s nullglob;shopt -s dotglob; echo *)) | |
if [ ${#files[@]} -gt 0 ]; then | |
seek_confirmation "Directory not empty, do you want to empty the directory?" | |
if is_confirmed; then | |
$(shopt -s nullglob;shopt -s dotglob;rm *) | |
else | |
e_error "Aborting sample file prep - directory not empty" | |
exit 44 | |
fi | |
fi | |
e_debug "Creating $numFiles random sample $ext files" | |
START=1 | |
for i in $(eval echo "{$START..$numFiles}") | |
do | |
echo $RANDOM > "$i.$ext" | |
done | |
# create some dupes | |
e_debug "Creating 3 duplicate $ext files" | |
if file_exists "1.$ext"; then | |
cp 1.png xx1.$ext | |
cp 1.png xxx1.$ext | |
cp 1.png xxxx1.$ext | |
else | |
e_warning "Dupe files not created" | |
fi | |
e_success "prepSampleFiles complete" | |
exit 77 | |
} | |
function usage { | |
me=$(basename ${BASH_SOURCE[0]}) | |
e_header "Usage: $me [-p [NUM]] [-e EXT]" | |
echo | |
echo "Rename all $ext files in the current directory to have a unique 5 character alphanumeric name" | |
echo 'Usually just run with no options' | |
echo | |
echo 'Options:' | |
echo -e '\t-p - prepare 100 (default) sample files in the current directory' | |
echo -e '\t-p NUM - prepare NUM sample files in the current directory' | |
echo -e '\t-e EXT - file extension of the files to be renamed' | |
exit 55 | |
} | |
printDupes(){ | |
local_array=("${@}") | |
e_warning "Dupes:" | |
for index in ${!local_array[*]} | |
do | |
e_debug "${local_array[$index]}" | |
done | |
} | |
# disappointing bit of code repetition here | |
# could be refactored | |
perlRandom(){ | |
declare -a moreDupes=() | |
local_dupes=("${@}") | |
e_header "Renaming ${#local_dupes[@]} dupe[s] with Perl" | |
for index in ${!local_dupes[*]} | |
do | |
newName=$(perl -e '@chars = ("A".."Z", "a".."z", 0 .. 9); $rand .= $chars[rand @chars] for 1..5; print $rand;') | |
e_debug "renaming ${local_dupes[$index]} to $newName.$ext" | |
# if the new file already exists, add to dupes array | |
# mv -nv means no overwriting and be verbose so we can match the output | |
if [[ $(mv -nv "${local_dupes[$index]}" $newName.$ext | tail -n1) =~ overwritten$ ]]; then | |
moreDupes=("${moreDupes[@]:+${moreDupes[@]}}" "${local_dupes[$index]}" ) | |
e_warning "Dupe, not renaming" | |
fi | |
done | |
#echo "foo ${moreDupes[@]}" # this fails if there are no more dupes moreDupes[@]: unbound variable | |
count=${#moreDupes[@]} # but this is OK if moreDupes[@] is not set .. weird | |
if [ $count -gt 0 ]; then | |
e_debug "More dupes" | |
printDupes "${moreDupes[@]:+${moreDupes[@]}}" | |
perlRandom "${moreDupes[@]:+${moreDupes[@]}}" | |
else | |
e_success "All files renamed" | |
exit 0 | |
fi | |
} | |
renameDupes(){ | |
declare -a moreDupes=() | |
local_dupes=("${@}") | |
e_header "Renaming ${#local_dupes[@]} dupe[s] with $shasumCmd" | |
for index in ${!local_dupes[*]} | |
do | |
shahash=$($shasumCmd "${local_dupes[$index]}" | awk '{ print $1}'); | |
newName=$(echo "$shahash" | cut -c -5) | |
e_debug "renaming ${local_dupes[$index]} to $newName.$ext" | |
# if the new file already exists, add to dupes array | |
# mv -nv means no overwriting and be verbose so we can match the output | |
if [[ $(mv -nv "${local_dupes[$index]}" $newName.$ext | tail -n1) =~ overwritten$ ]]; then | |
moreDupes=("${moreDupes[@]:+${moreDupes[@]}}" "${local_dupes[$index]}" ) | |
e_warning "Dupe, not renaming" | |
fi | |
done | |
count=${#moreDupes[@]} | |
if [ $count -gt 0 ]; then | |
e_debug "More dupes" | |
printDupes "${moreDupes[@]:+${moreDupes[@]}}" | |
let "loopCount += 1" | |
if [ $loopCount -gt 4 ]; then | |
e_error "More dupes left. Trying Perl." | |
perlRandom "${moreDupes[@]:+${moreDupes[@]}}" | |
else | |
shasumCmd="shasum -a ${shaOps[$loopCount]}" | |
renameDupes "${moreDupes[@]:+${moreDupes[@]}}" | |
fi | |
else | |
e_success "All files renamed" | |
exit 0 | |
fi | |
} | |
# default extension | |
ext="png" | |
# quick arg check | |
if [ $# -eq 1 -a "${1:-unset}" = '--' ] || [ $# -gt 4 ]; then | |
usage | |
fi | |
extOpt="" | |
prepOpt="" | |
extArg=0 | |
prepArg=0 | |
for opt in "$@" | |
do | |
case $opt in | |
-e ) extOpt="${2:-}"; extArg=1; shift ;; | |
-p ) prepOpt="prepSampleFiles ${2:-}"; prepArg=1; shift ;; | |
-h | --help) usage ;; | |
-*|--*) e_warning "Warning: invalid option $opt" && usage;; | |
* ) shift;; | |
esac | |
done | |
if [ $extArg -eq 1 ]; then | |
if [ -z "$extOpt" ]; then | |
e_error "-e must have an argument. e.g. png" | |
usage | |
fi | |
fi | |
# must set ext first | |
if [ -n "$extOpt" ]; then | |
#e_debug "extOpt is $extOpt" | |
ext="$extOpt" | |
fi | |
if [ -n "$prepOpt" ]; then | |
#e_debug "prepOpt is $prepOpt" | |
eval "$prepOpt" | |
fi | |
# if no bad options, then we get to here, i.e. no options | |
e_header "Starting rename..." | |
# array to capture dupes | |
declare -a dupes=() | |
# file listing should be case-insensitive | |
for file in $(shopt -s nocaseglob; ls *.$ext); | |
do | |
mdhash=$(md5 -q "$file"); | |
newName=$(echo "$mdhash" | cut -c -5) | |
e_debug "renaming $file to $newName.$ext" | |
# if the new file already exists, add to dupes array | |
# mv -nv means no overwriting and be verbose so we can match the output | |
if [[ $(mv -nv $file $newName.$ext | tail -n1) =~ overwritten$ ]]; then | |
e_warning "Dupe, not renaming" | |
# the :+ operator is param expansion | |
# to get around the unbound variable error when array is empty | |
# see http://cloud.zoooot.com/Q3V4 | |
dupes=("${dupes[@]:+${dupes[@]}}" "$file" ) | |
fi | |
done | |
# counter to change the shasum args if needed | |
loopCount=0 | |
# shasum args and command | |
# used for renaming dupes | |
declare -a shaOps=(1 224 256 384 512) | |
shasumCmd="shasum -a ${shaOps[$loopCount]}" | |
# do we have any dupes? | |
count=${#dupes[@]} # but this is OK if dupes[@] is not set - no unbound variable error .. weird | |
if [ $count -gt 0 ]; then | |
printDupes "${dupes[@]:+${dupes[@]}}" | |
renameDupes "${dupes[@]:+${dupes[@]}}" | |
else | |
e_success "All files renamed" | |
fi | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment