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