inc@tc.fluke.COM (Gary Benson) (04/27/88)
Hello, I recently subscribed to this group to see if it's an appropriate place to ask a question I've had for some time now. It seems to be, so here goes: I work in a publications department, and in the nature of our business, we create, rename, and destroy a LOT of files. A typical directory may have many similar file names. Wildcards help in deleting unneeded files, but not in copying or moving them. For example, consider the following files in a directory associated with a technical manual: QT.1.r QT.4.r QT.A.r QT.2.r QT.5.r QT.annotations.r QT.3.r QT.6.r QT.toc.r For information only, the product is called QuickTools, there is one file per section of the manual (1 through 6), one for Appendix A, one for illustration annotations, and the table of contents. In preparing this manual for production, I run a shell script called "prep" that gets rid of extra spacing, intermediate formatting commands, comments and so on, and creates an output file for each input file. Now my directory now looks like this: QT.1.r QT.4.r QT.A.r Qt.1.r.pre QT.4.r.pre QT.A.r.pre QT.2.r QT.5.r QT.annotations.r QT.2.r.pre QT.5.r.pre QT.annotations.r.pre QT.3.r QT.6.r QT.toc.r QT.3.r.pre QT.6.r.pre QT.toc.r.pre Now I want to rename all those ".pre" files to the same name without ".pre". In other words, I want the directory to look like it did when I began, (like separate mv commands, or cp followed by rm *.pre) separate mv and I realize that a smarter shell script could have taken care of this as part of the prepping process, but there are many ways that people in our group wind up with associated files with similar filenames they want to rename all at once. The alternative (separate 'mv' commands for each section) is time-consuming and error prone. 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 -or even- rename QT.?.r.pre \#.r (to change QT.1.r.pre to 1.r, etc) Hopefully a -f option would do it without question, -i would ask before blowing away the file of the same name and -i being the default. No -r option! Has anyone invented such a thing? If so, could you send me a copy? If not, can anyone explain a workable approach to doing this? I'd appreciate any help you can give me. ___ Gary Benson -_-_-_-_-_-_-_-_-inc@tc.fluke.com_-_-_-_-_-_-_-_-_-_ Publication Services Ensign Benson, Space Cadet, Digital Circus, Sector R John Fluke Mfg. Co. Inc. _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_- -- Gary Benson Publication Services -=[ inc : 5367 : 232E ]=-
bowles@lll-crg.llnl.gov (Jeff Bowles) (04/27/88)
Hmm. Hard to do directly, without hacking the shell's view of metacharacters. Perhaps you want something like this: rename '\(.*\).f' *.f in which the expression is something normally given to expr(1). Such a script would follow this form: #!/bin/sh ex=$1 shift for f in $* do newf=`expr $f : "$ex"` mv $f $newf done Of course you'd embellish this, make it possible to pass flags to the mv(1) command, and provide for files with "#" in the name, but I submit that to ignore the existing tools would not only waste your time, but run the risk of making a new tool that doesn't fit in well with the existing ones. [ "Isn't it neat when you can spell your name with the different flags you've added to a command?" - overheard at a Usenix a while back.] Jeff Bowles
gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/27/88)
In article <3564@fluke.COM> inc@tc.fluke.COM (Gary Benson) writes: >Now I want to rename all those ".pre" files to the same name without ".pre". What I usually do in such circumstances is: for i in *.pre; do mv $i `basename $i .pre`; done
davidsen@steinmetz.ge.com (William E. Davidsen Jr) (04/28/88)
As long as the rename is the way you describe, "rename a file with a suffix to be the same name without the siffix" the solution is easy. It used sh (or ksh) as written: for src in *.suffix # all names of this type do dest=`basename $src .suffix` # strip the suffix mv $src $dest # and move the file done I don't have access to a pure BSD system to see if basename is there; it's in Ultrix and SunOS which are as close as I come. -- bill davidsen (wedu@ge-crd.arpa) {uunet | philabs | seismo}!steinmetz!crdos1!davidsen "Stupidity, like virtue, is its own reward" -me
decot@hpcupt1.HP.COM (Dave Decot) (04/28/88)
To move *.r.pre to *.r, do this: % sh $ for i in *.pre > do > name=`echo $i | sed 's/.pre$//'` > mv $i $name > done $ exit % Dave Decot hpda!decot
hunt@csli.STANFORD.EDU (Brian Hunt) (04/28/88)
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
rbj@icst-cmr.arpa (Root Boy Jim) (05/04/88)
From: Gary Benson <inc@tc.fluke.COM> Hello, Good morning, Mister Benson, I see you're doing well... Now I want to rename all those ".pre" files to the same name without ".pre". As usual, Doug Gwyn posted the quickest, most succinct, and most universal solution (I do say something nice about him every once in awhile :-). Some of the other solutions that were posted were incredibly unwieldy, and their posters should rethink their approach to the problem. Repent heathens! However, for those of us with the csh, there is yet another solution: foreach x (*.pre) mv $x $x:r end This may be typed directly into the shell, but only works with suffixes delimited with dots. Multiple dots work, so `set x=a.b.c; echo $x:r' yields `a.b'. You may add the -f or -i flags directly to mv if desired. Gary Benson -_-_-_-_-_-_-_-_-inc@tc.fluke.com_-_-_-_-_-_-_-_ Publication Services Ensign Benson, Space Cadet, Digital Circus, Sector R John Fluke Mfg. Co. Inc. _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_- (Root Boy) Jim Cottrell <rbj@icst-cmr.arpa> National Bureau of Standards Flamer's Hotline: (301) 975-5688 The opinions expressed are solely my own and do not reflect NBS policy or agreement Sign my PETITION.
ctr@Stride.COM (Chris Reimer) (05/05/88)
In article <3564@fluke.COM> inc@tc.fluke.COM (Gary Benson) writes: > > QT.1.r QT.4.r QT.A.r > Qt.1.r.pre QT.4.r.pre QT.A.r.pre > >Now I want to rename all those ".pre" files to the same name without ".pre". Try: foo% foreach i ( `ls *.pre | sed 's/.pre$//'` ) ? echo "Moving ${i}..." ? mv ${i}.pre $i ? end Obviously (I hope), this must be run under csh. Enjoy! --- Christian Reimer "Through Truth and Justice, Virtue will Grow!" ctr@xpiinc.uu.net - The Salamander ...!uunet!xpiinc!ctr ---
amoss%HUJINIX.BITNET@cunyvm.cuny.edu (Amos Shapira) (05/09/88)
Chris Reimer (ctr@stride.com) writes: >In article <3564@fluke.COM> inc@tc.fluke.COM (Gary Benson) writes: >> >> QT.1.r QT.4.r QT.A.r >> Qt.1.r.pre QT.4.r.pre QT.A.r.pre >> >>Now I want to rename all those ".pre" files to the same name without ".pre". > >Try: > foo% foreach i ( `ls *.pre sed 's/.pre$//'` ) > ? echo "Moving ${i}..." > ? mv ${i}.pre $i > ? end > >Obviously (I hope), this must be run under csh. Enjoy! Could make it simpler, and much more importnt, faster. My suggestion is to use basename(1), like this: % foreach i (*.pre) ? echo Moving $i... ? mv $i `basename $i .pre` ? end basename(1) is under /usr/bin, so I'm not sure if it comes with SV systems. But you can write one for yourself. Maybe the forking of a new basename program for each file is slower than running one, a bit bigger, sed, but after the first time the basename program is loaded, it stays in memory, and so the rest should take much faster. Also basename is much simpler than sed. If you still want to use Chris's idea, be carefull to use /bin/ls, to prevent aliasing (here at HU, people like to alias ls to use the -F flag, which may break Chris's solution). Have fun! --Amos Shapira The Hebrew University of Jerusalem, Israel. ============================================================================== BITNET: amoss@hujinix.bitnet CSnet: amoss%shum.huji.ac.il@relay.cs.net UUCPnet: ucbvax!shum.huji.ac.il!amoss Domain-Style: amoss@shum.huji.ac.il ============================================================================== "Super users do it without asking for permission." - me
davy@ea.ecn.purdue.edu (Dave Curry) (05/09/88)
In article <13840@brl-adm.ARPA> amoss%HUJINIX.BITNET@cunyvm.cuny.edu (Amos Shapira) writes: >Chris Reimer (ctr@stride.com) writes: >> >>Try: >> foo% foreach i ( `ls *.pre sed 's/.pre$//'` ) >> ? echo "Moving ${i}..." >> ? mv ${i}.pre $i >> ? end >> >>Obviously (I hope), this must be run under csh. Enjoy! > > Could make it simpler, and much more importnt, faster. > My suggestion is to use basename(1), like this: > > % foreach i (*.pre) > ? echo Moving $i... > ? mv $i `basename $i .pre` > ? end > > basename(1) is under /usr/bin, so I'm not sure if it > comes with SV systems. But you can write one for yourself. If you're going for speed, then forking and execing basename for every file name is certainly not the solution. I suspect for any number of files greater than 3 or 4, the ls/sed answer is faster. But, both of you are doing things the wrong way. If you're going to use "csh", then instead of simply writing an "sh" script in "csh" syntax, you might as well use some of "csh"'s useful features, namely the colon modifiers (or whatever they're called): % foreach i (*.pre) ? echo Moving $i... ? mv $i $i:r ? end The ":r" operator removes the first (working from the right) ".anything" from a file name. It's exactly equivalent to your basename version above, only about a zillion times faster. There are other colon modifiers which let you take the basename of a file (:t), the directory part of a file name (:h), and the extension (.anything) part of a file name (:e). And yes, it's all documented in the manual page, this isn't secret magic stuff. --Dave Curry
rrr@naucse.UUCP (Bob Rose ) (05/10/88)
Amos Shapira writes: > Chris Reimer writes: > >Gary Benson writes: > >> QT.1.r QT.4.r QT.A.r > >> Qt.1.r.pre QT.4.r.pre QT.A.r.pre > >>Now I want to rename all those ".pre" files to the same name without ".pre". > > foo% foreach i ( `ls *.pre sed 's/.pre$//'` ) > > ? echo "Moving ${i}..." > > ? mv ${i}.pre $i > > ? end > > Could make it simpler, and much more importnt, faster. > % foreach i (*.pre) > ? echo Moving $i... > ? mv $i `basename $i .pre` > ? end So we want to make this one time command run faster, then why are we running `basename' for each arguement. Lets use the real power of the csh. % foreach i (*.pre) ? echo Moving $i... ? mv $i $i:r ? end This may also be to slow also. Has anybody modified `mv' to move files to their basename. Something like % mv -b *.pre :^) 8^) :`) O^) ;^) |^) :~) :^} :^] &^) %^) :^{) X^) (Hopefully thats enough)
jcl@bdrc.COM (John C. Lusth) (05/10/88)
>In article <3564@fluke.COM> inc@tc.fluke.COM (Gary Benson) writes: > > QT.1.r QT.4.r QT.A.r > Qt.1.r.pre QT.4.r.pre QT.A.r.pre > >Now I want to rename all those ".pre" files to the same name without ".pre". Here is a shell script that renames portions of filenames: #!/bin/csh ######################################################### # # mv+ pattern1 pattern2 file1 [ file2 ... ] # # rename files by replacing the last pattern1 with pattern2 set x = $1 # what it was shift set y = $1 # what it shall be shift foreach f ( $* ) if ( `expr match $f '.*'$x'.*'` ) then set a = `expr match $f '\(.*\)'$x'.*'` set b = `expr match $f '.*'$x'\(.*\)'` echo mv $f $a$y$b mv $f $a$y$b else echo $f not moved. endif end echo finished. #################################################################### If you were to name this script mv+ ( I for the life of me can't think up a good name for it), the following command would accomplish your task mv+ .pre "" * Every once in a while, this shell script can be quite useful. You can also do things like mv+ "[abc]" z * which replaces the last letter a, b, or, c with z in any file names containing an a, b, or, c. Messing around with regular expressions can be hazardous though. In general, one should use literals for pattern1. John C. Lusth Becton Dickinson Research Center Research Triangle Park, NC ...!mcnc!bdrc!jcl
jcl@bdrc.COM (John C. Lusth) (05/11/88)
In article <324@bdrc.UUCP> jcl@bdrc.UUCP (John C. Lusth) writes:
<Here is a shell script that renames portions of filenames:
<
<#!/bin/csh #########################################################
<#
<# mv+ pattern1 pattern2 file1 [ file2 ... ]
<#
<# rename files by replacing the last pattern1 with pattern2
<
[shell script and text deleted ]
<
<Every once in a while, this shell script can be quite useful. You can
<also do things like
<
< mv+ "[abc]" z *
<
<which replaces the last letter a, b, or, c with z in any file names containing
<an a, b, or, c. Messing around with regular expressions can be hazardous
<though. In general, one should use literals for pattern1.
Oops. In order to use regular expressions for pattern1, insert the line
set noglob
in the beginning of the script. Sorry about that.
John C. Lusth
Becton Dickinson Research Center
Research Triangle Park, NC
...!mcnc!bdrc!jcl
cudcv@daisy.warwick.ac.uk (Rob McMahon) (05/11/88)
In article <784@stride.Stride.COM> ctr@xpiinc.uu.net (Christian Reimer) writes: >In article <3564@fluke.COM> inc@tc.fluke.COM (Gary Benson) writes: >>Now I want to rename all those ".pre" files to the same name without ".pre". > >Try: > foo% foreach i ( `ls *.pre | sed 's/.pre$//'` ) > ? echo "Moving ${i}..." > ? mv ${i}.pre $i > ? end Or even foo% foreach i ( *.pre ) ? echo "Moving ${i}..." ? mv $i $i:r ? end Rob -- UUCP: ...!mcvax!ukc!warwick!cudcv PHONE: +44 203 523037 JANET: cudcv@uk.ac.warwick.cu ARPA: cudcv@cu.warwick.ac.uk Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England
leo@philmds.UUCP (Leo de Wit) (05/20/88)
In article <2956@ea.ecn.purdue.edu> davy@ea.ecn.purdue.edu.UUCP (Dave Curry) writes: > ...[stuff deleted]... >>>Try: >>> foo% foreach i ( `ls *.pre sed 's/.pre$//'` ) >>> ? echo "Moving ${i}..." >>> ? mv ${i}.pre $i >>> ? end > ...[stuff deleted about someone using basename each time in the loop]... > >If you're going for speed, then forking and execing basename for every >file name is certainly not the solution. I suspect for any number of >files greater than 3 or 4, the ls/sed answer is faster. > ...[further discussion using csh features]... I agree about not using basename inside the loop (besides, sed is not that big and you use it only once), but still like the sed solution more; it is more flexible and more 'Un*x-style': let each tool do it's own dedicated job. Sed is good at conversions. I used a similar construct to rename VMS (have to clean my mouth now 8-) filenames to Un*x filenames, i.e. lowercase conversion, version stripping. Sed can do just that, e.g. ------------- Start Here ------------- #!/bin/sh set `ls *\;* 2>/dev/null |sed ' p s/\([^ ]*\);[0-9]*/\1/ y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` # The positional parameters now are: oldname1 newname1 oldname2 newname2 etc. while : do case $# in 0) exit 0;; esac mv $1 $2 shift; shift done ------------- End Here ------------- and you can do all other kinds of conversions, too. Leo.