In Unix, how do I rename *.foo to *.bar, or change filenames to lowercase?
In Unix, if you are attempting to change the extension for
multiple files, you may be tempted to try the command mv
*.foo *.bar thinking that this will move each file ending in
.foo to a new file ending in .bar.
When considering why this command does not work, think about how the
shell
expands wildcards. Before the mv command ever sees the
arguments, *.foo and *.bar are expanded.
Depending on your shell, this can fail in a couple of ways. The
csh shell prints "No match", because it can't match
*.bar . The sh shell executes mv
a.foo b.foo c.foo *.bar , which will only succeed if you
happen to have a single directory named *.bar
(which is very unlikely and almost certainly not what you had in
mind).
Depending on your shell, you can accomplish this with a loop to
mv each file individually. If your system has
basename, you can use:
- C shell foreach f ( *.foo ) set base=`basename $f .foo` mv $f $base.bar end
- Bourne or Korn shell for f in *.foo; do base=`basename $f .foo` mv $f $base.bar done
Some shells have their own variable substitution features, so instead
of using basename, you can use simpler loops like:
- C shell foreach f ( *.foo ) mv $f $f:r.bar end
- Korn shell for f in *.foo; do mv $f ${f%foo}bar done
If you don't have basename or want to do something
similar to renaming foo.* to bar.* ,
you can use a command such as sed to strip apart the
original filename in other ways, but the general looping idea is the
same. You can also convert filenames into mv commands
with sed , and hand the commands off to
sh for execution. Try the following:
ls -d *.foo | sed -e 's/.*/mv & &/' -e 's/foo$/bar/' | sh
A program by Vladimir Lanin called mmv that does this job
nicely was posted to comp.sources.unix (Volume 21, issues
87 and 88) in April 1990. It lets you use the following:
mmv '*.foo' '=1.bar'
You can use shell loops like the above to translate filenames from
upper- to lowercase or vice versa. Use something like this to rename
uppercase files to lowercase:
- C shell foreach f ( * ) mv $f `echo $f | tr A-Z a-z` end
- Bourne shell for f in *; do mv $f `echo $f | tr A-Z a-z` done
- Korn shell typeset -l l for f in *; do l="$f" mv $f $l done
If you wish to be extremely thorough and handle files with unusual names (e.g., embedded blanks) you'd need to use:
- Bourne shell for f in *; do g=`expr "xxx$f" : 'xxx\(.*\)' | tr '[A-Z]' '[a-z]'` mv "$f" "$g" done
The expr command will always print the filename, even if
it equals -n or if it contains a System V escape sequence (e.g.,
\c ).
If you have the Perl language installed, you may find this rename script by Larry Wall very useful; you can use it to accomplish a wide variety of filename changes: #!/usr/bin/perl # # rename script examples from lwall: # rename 's/\.orig$//' *.orig # rename 'y/A-Z/a-z/ unless /^Make/' * # rename '$_ .= ".bad"' *.f # rename 'print "$_: "; s/foo/bar/ if <stdin> =~ /^y/i' * $op = shift; for (@ARGV) { $was = $_; eval $op; die $@ if $@; rename($was,$_) unless $was eq $_; }
Note: This information comes from the Unix
FAQ, which is posted regularly to the Usenet
newsgroups comp.unix.questions and
comp.unix.shell. You can obtain it by FTP from
rtfm.mit.edu in the /pub/usenet directory,
and on the web at:
http://www.faqs.org/faqs/unix-faq/faq/
At Indiana University, for personal or departmental Linux or Unix systems support, see At IU, how do I get support for Linux or Unix?
Last modified on August 22, 2008.







