If you have a group of files whose names end with .new and you want to rename them to end with .old, you might try something like the following:
% mv *.new *.old Wrong!
However, this won't work because the shell can't match *.old and because the mv command just doesn't work that way. Here's one way to do it that will work with most shells:
-d Section 8.5, \(..\)..\1 Section 34.11
$ ls -d *.new | sed "s/\(.*\)\.new$/mv '&' '\1.old'/" | sh % ls -d *.new | sed 's/\(.*\)\.new$/mv "&" "\1.old"/' | sh
That outputs a series of mv commands, one per file, and pipes them to a shell (Section 3.4). The quotes help make sure that special characters (Section 27.17) aren't touched by the shell -- this isn't always needed, but it's a good idea if you aren't sure what files you'll be renaming. Single quotes around the filenames are "strongest"; we use them in the Bourne-type shell version. Unfortunately, csh and tcsh don't allow $ inside double quotes unless it's the start of a shell variable name. So the C shell version puts double quotes around the filenames -- but the Bourne shell version can use the "stronger" single quotes, like this:
mv 'afile.new' 'afile.old' mv 'bfile.new' 'bfile.old' ...
To copy, change mv to cp. For safety, use mv -i or cp -i if your versions have the -i options (Section 14.15). Using sh -v (Section 27.15) will show the commands as the shell executes them.
This method works for any Unix command that takes a pair of filenames. For instance, to compare a set of files in the current directory with the original files in the /usr/local/src directory, use diff:
% ls -d *.c *.h | sed 's@.*@diff -c & /usr/local/src/&@' | sh
Note that diff -r does let you compare entire directories, but you need a trick like this to only compare some of the files.
--JP and DJPH
Copyright © 2003 O'Reilly & Associates. All rights reserved.