Mass File Renamer: By Pattern Substitution
Posted 09-13-2008 at 10:37 PM by ghostdog74
Code:
#!/bin/bash
## Change file names with a pattern substitution.
NO_ARGS=0
E_OPTERROR=65
DEBUG=0
FNAME="f"
maxdepth=1
directory=`pwd`
set -o noglob
#---- Functions ------------#
usage() {
printf "Usage: `basename $0` [-D directory] [-M depth] [-s pattern_from ] [-e pattern_to ] [-d] [-X] [filename(s)]\n"
cat << 'EOF'
-D : starting directory. Default=current directory
-M : max depth to recurse subdirectories (default=1), eg 1,2
-s : pattern to change from. Can be simple shell patterns. eg [0-9], [a-z], "pattern1|pattern2".
To input special characters, eg "[\`&*]",'[`&*]'
-e : pattern to change to. To rename to null, use "". eg -e ""
-d : Debugging mode. Used to list all files to be changed, without changes taking effect
-X : Only check directory names, not file names
filename(s) : file names eg *.txt. If omitted, default to all files
Example: -s file -e test -d *.txt ===> change all name of text files
with pattern "file" to "test". eg file_copy.txt will be changed to test_copy.txt
EOF
}
#----------------------------#
if [ $# -eq "$NO_ARGS" ] # Script invoked with no command-line args?
then
usage
exit $E_OPTERROR # Exit and explain usage, if no argument(s) given.
fi
while getopts "D:s:e:M:Xd" Option
do
case $Option in
D ) directory=$OPTARG
;;
s ) startseq=$OPTARG
[ -z "${startseq}" ] && echo "Pattern not specified. Use -s <pattern_from> and -e <pattern_to>" && exit
;;
e ) endseq=$OPTARG
[ -z "${endseq}" ] && endseq=""
;;
d ) DEBUG=1 ;;
X ) FNAME="d";;
M ) maxdepth=$OPTARG
case ${maxdepth} in
0 | *[a-z]* |"") maxdepth=1;;
esac
;;
* ) echo "Unimplemented option chosen."
exit;;
esac
done
shift $(($OPTIND - 1))
# get last argument
argument=$#
if [ $argument -eq 0 ];then
ext="*"
else
ext=$(eval echo \"\${${argument}}\")
fi
find "${directory}" -maxdepth ${maxdepth} -type "${FNAME}" -name "$ext" -printf "%f:%h:%p\n" | \
awk -F":" -v startseq="${startseq}" -v endseq="${endseq}" -v debug="$DEBUG" 'BEGIN{}
$1 ~ startseq{
original=$1
sq="\047"
q="\042"
flag=0
s = gsub (startseq, endseq,$1 )
if ( startseg ~ /'"\'"'/) { sq="\042" }
if ( startseq ~ /[[:punct:]]/ ) { flag=1} #if found special characters/punctuation
if ( debug) {
if(flag) { print "mv -u " q $2"/" q sq original sq " "q $2 "/" $1 q }
else{ print "mv -u " q $3 q " "q $2 "/" $1 q }
}
else {
if(flag) { cmd= "mv -u " q $2"/" q sq original sq " "q $2 "/" $1 q }
else{ cmd = "mv -u " q $3 q " "q $2 "/" $1 q }
system(cmd)
}
}'
Usage:
The script makes use of GNU find/awk. Maximum depth value passed to "find" is set to default 1 level. Issue -M <level> to recurse more than 1 level of subdirectories. File types is set to search for files by default. Issue -X to search for directory names. If -D <directory> is omitted, the script searches from current working directory onwards.
# Execute the script name without any arguments to show help.
> ./script.sh
# To see results before making actual changes, use the -d switch.
> ./script.sh -D /path/1 -M 2 -s "from" -e "to" [color=red]-d[/code] "*.txt"
# To rename files with extension ".txt" and word "image" in their file names to "file" and search directories for 2 levels.
> ./script.sh -D /path/1 -M 2 -s "image" -e "file" "*.txt"
# To rename all files in the current directory with word "file" or "image" to "test" without traversing directories
> ./script.sh -s "file|image" -e "test" -d
# To rename all files in current directory with more than 1 numbers to "test".
> ./script.sh -s "[0-9]+" -e "test" -d
# To replace special characters eg ' (single quote), & ,!
> ./script.sh -s "[!]" -e "" -d









