Path: utzoo!mnetor!uunet!husc6!bbn!rochester!udel!gatech!purdue!decwrl!labrea!csli!hunt From: hunt@csli.STANFORD.EDU (Brian Hunt) Newsgroups: comp.unix.questions Subject: Re: Need a file renaming facility Message-ID: <3667@csli.STANFORD.EDU> Date: 28 Apr 88 14:24:35 GMT References: <3564@fluke.COM> Reply-To: hunt@csli.UUCP (Brian Hunt) Organization: Center for the Study of Language and Information, Stanford U. Lines: 95 In article <3564@fluke.COM> inc@tc.fluke.COM (Gary Benson) writes: >What I'm looking for is a general-purpose >renaming facility that (I hope) takes wild cards, with this kind of synatax: > > rename -f QT.?.r.pre QT.?.r > > -or- > > rename QT.*.r.pre QT.*.r This may be overkill, but here's a shell script I've been using for some time to do often complicated renaming of multiple files. It's probably rather clumsy, but has worked quite well for me. I'm sure there are many possibilties I haven't tried, though, so USE AT YOUR OWN RISK. I just added the part that passes flags to mv(1), so that bit is relatively untested. I'm sure it has a relatively limited set of characters it can handle in a filename; one possibly unexpected character it will choke on is ':', since that's what the script uses as the delimiter for the sed(1) substitution function. Beats choking on '/', at least... The syntax is as follows: rename [-flags] "exp1" "exp2" where exp1 describes the files to be renamed using the wildcards '?' and '*', and exp2 gives the pattern for the new names of the files using the same sequence of wildcards as exp1. For example, rename -i "a*b?*c" "x*?y*z" would use "mv -i" to move files a12b345c and a1b2c to x123y45z and x12yz, respectively, while leaving the file a12bc unchanged. That is, each wildcard in exp2 is replaced by the string which was matched by the corresponding wildcard in exp1. In addition, if a wildcard in exp2 is preceded by a tilde, the corresponding string is dropped from the destination filename (possibly making it non-unique.) So, rename "*.*" "*~*" would move files a.b, a.c, and b.c to a, a, and b respectively, thus losing the contents of a.b. Probably best to always use -i option when using this feature... Note that the arguments to rename must be quoted somehow in order for the wildcards not to be globbed away. To save me from worrying about this, I have the following in my .cshrc: alias ren 'rename -i "\!:1" "\!:2"' At most nine wildcards are allowed. All filename changes are echoed on the standard output. Finally, here is the script. Feel free to use, copy, and modify it as you please, with or without attribution; i.e., it's all yours... Brian Hunt Dept. of Mathematics Stanford University #!/bin/csh -f set noglob set flags while (`echo "$1" | cut -c1` == "-") set flags=($flags $1) shift end if (`echo "$1" | sed 's:[^?*]::g'` != `echo "$2" | sed 's:[^?*]::g'`) then echo "rename: Please use same wildcards in both arguments." exit 1 endif unset noglob set files=$1 set noglob set oldexp=`echo "$1" | sed -e 's:?:\\(.\\):g' -e 's:\*:\\(.*\\):g'` set newexp="$2" foreach digit (1 2 3 4 5 6 7 8 9) set tmpexp=`echo "$newexp" | sed 's:[?*]:\\'"$digit":` if ("$tmpexp" == "$newexp") then break else set newexp="$tmpexp" endif end if (`echo "$newexp" | grep -c '[?*]'` > 0) then echo "rename: Too many wildcards." exit 2 endif set newexp=`echo "$tmpexp" | sed 's:~\\[1-9]::g'` foreach oldfile ($files) set newfile=`echo "$oldfile" | sed s:^"$oldexp"\$:"$newexp":` echo "moving $oldfile to $newfile" mv $flags "$oldfile" "$newfile" end exit 0