Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I've got about 15 lots of 100+ directories, specifically using pseudocode how can you:

rename * *suffix  
rename * prefix*  
rename * CAPITALIZE*

BUT tips or links to tutorials specific to working with multiple files and directories would be appreciated.

share|improve this question

6 Answers 6

up vote 5 down vote accepted

Many linux/unix systems come with a rename or rename.pl or prename perl-script that allows renaming via perl expressions. On Debian systems, it's installed with the perl package.

$ rename
Usage: rename [-v] [-n] [-f] perlexpr [filenames]

The magic happens in the perlexpr argument. This is essentially a short bit of perl code that will operate on each filename. You don't need to provide any loops, just write code that transforms your input into the desired output. (Be sure and quote the expression; I use single-quotes to protect against shell expansion unless it's absolutely necessary.)

So, for your examples:

  • rename * *suffix

    $ rename 's/$/suffix/' *
              ^ ^  ^^^^
              | |    +-- your suffix goes here
              | +------- indicates end-of-string
              +--------- perl's substitution operator (s/from-regex/to/)
    
  • rename * prefix*

    $ rename 's/^/prefix/' *
                ^  ^^^^
                |    +-- your prefix goes here
                +------- indicates beginning-of-string
    
  • rename * CAPITALIZE*

    $ rename '$_ = uc' *
              ^^^^ ^^
               |    +-- perl builtin function to capitalize a string
               +------- replaces input filename
    

See more examples from the O'Reilly Unix Power Tools book.

share|improve this answer
    
But, with care, it can all be done in one operation! –  Jonathan Leffler Oct 31 '09 at 4:57
    
sure! i'm assuming three different examples, not three operations in a single example. –  quack quixote Oct 31 '09 at 5:11
    
If you are unsure about the regex you are using, add the -v and -n flags, which will show the renames that would happen, but not actually perform them. –  Andrew Ferrier Feb 14 '13 at 12:44

This will work for prefix and suffix additions to all file names.

find /base/dir/path -type f -exec mv {} prefix{}suffix \;
#                                    -- ^^^^^^--^^^^^^

For the capitalization you could probably write a short bash loop that will used something like a sed to change the letter case and then move.

I will suggest reading,

  1. Advanced Bash Scripting Guile
  2. Perl scripting
share|improve this answer

I'd use Perl - and specifically this modified version of a 'rename' script that was in the 1st Edition of the Camel book (but dropped from the second and third editions for lack of space).

Usage:

find . -type f -print0 | xargs -0 rename 's%/([^/]+)$%/prefix\U${1}\Esuffix%'

Which, being translated, means:

  • find all the files, even those with blanks in their name, and handle them properly.
  • for each file name, find the name after the last slash, remembering it as '${1}'
  • replace the name with 'prefix', the upper-case version of what was remembered, and 'suffix'

So, the whole job can be done in one command with a sufficiently versatile tool.


#!/Users/jleffler/perl/v5.10.0/bin/perl -w
#
# @(#)$Id: rename.pl,v 1.7 2008/02/16 07:53:08 jleffler Exp $
#
# Rename files using a Perl substitute or transliterate command

use strict;
use Getopt::Std;

my(%opts);
my($usage) = "Usage: $0 [-fnxV] perlexpr [filenames]\n";
my($force) = 0;
my($noexc) = 0;
my($trace) = 0;

die $usage unless getopts('fnxV', \%opts);

if ($opts{V})
{
    printf "%s\n", q'RENAME Version $Revision: 1.7 $ ($Date: 2008/02/16 07:53:08 $)';
    exit 0;
}
$force = 1 if ($opts{f});
$noexc = 1 if ($opts{n});
$trace = 1 if ($opts{x});

my($op) = shift;
die $usage unless defined $op;

if (!@ARGV) {
    @ARGV = <STDIN>;
    chop(@ARGV);
}

for (@ARGV)
{
    if (-e $_ || -l $_)
    {
        my($was) = $_;
        eval $op;
        die $@ if $@;
        next if ($was eq $_);
        if ($force == 0 && -f $_)
        {
            print STDERR "rename failed: $was - $_ exists\n";
        }
        else
        {
            print "+ $was --> $_\n" if $trace;
            print STDERR "rename failed: $was - $!\n"
                unless ($noexc || rename($was, $_));
        }
    }
    else
    {
        print STDERR "$_ - $!\n";
    }
}


For whatever it is worth, I ran into a persistent failure that was not dreadfully informative when I tried:

$ find . -type f -print0 | xargs -0 rename 's/.*/prefix$&suffix/'
rename failed: ./xxx-32 - No such file or directory
rename failed: ./xxx-64 - No such file or directory
rename failed: ./xxx.c - No such file or directory
rename failed: ./xxx.c~ - No such file or directory
$

That was odd - I can see those files...

Using the '-x' option to 'rename' told me what the trouble was, though:

rename failed: ./xxx-32 - No such file or directory
rename failed: ./xxx-64 - No such file or directory
rename failed: ./xxx.c - No such file or directory
rename failed: ./xxx.c~ - No such file or directory
+ ./xxx-32 --> prefix./xxx-32suffix
+ ./xxx-64 --> prefix./xxx-64suffix
+ ./xxx.c --> prefix./xxx.csuffix
+ ./xxx.c~ --> prefix./xxx.c~suffix

Oh right - there isn't a sub-directory called 'prefix.' in my current directory!

share|improve this answer
    
+1 for find -print0 | xargs -0 –  Chris Johnsen Oct 31 '09 at 9:35
    
@Jonathan Leffler: I feel that you have both blessed and tormented me, as your script is a godsend ... yet I feel I must learn another language, namely PERL, immediately. :) Thank You, very much. –  Ande Oct 31 '09 at 14:25

For the caps-to-lowercase, how about:

for filename in *                # Traverse all files in directory.
do
   fname=`basename $filename`
   n=`echo $fname | tr A-Z a-z`  # Change name to lowercase.
   if [ "$fname" != "$n" ]       # Rename only files not already lowercase.
   then
     mv $fname $n
   fi  
done

Stolen shamelessly from the Linux Documentation Project: http://tldp.org/LDP/abs/html/textproc.html

Has to be easier (and resource-lighter) than using Perl.

share|improve this answer
1  
That will not change the names of the files, just uppercase the contents of the files (and dump that to stdout). –  Chris Johnsen Oct 31 '09 at 9:36

I like Perl rename the best, if you have it or can get it.

Here are some UPPERCASE variations:

# take out the echo to make these do the work

# find + xargs + bash (v4) + mv
# requires bash 4 for the ^^ uppercasing feature
find * -type f -print0 | xargs -0 bash -c 'for f in "$@"; do dir="";case "$1" in (*/*) dir="${f%/*}/";;esac;filename="${f##*/}"; echo mv "$f" "$dir${filename^^}"; done' mv

# find + xargs + sh + dirname + basename + tr + mv
# maybe easier to understand than above, but noticeably slower due to 3 forks per file
find * -type f -print0 | xargs -0 sh -c 'for f in "$@"; do echo mv "$f" "$(dirname "$f")/$(printf "$(basename "$f")" | tr "[:lower:]" "[:upper:]")"; done' mv

I have been playing around with zsh lately, so here are the zmv invocations:

# If the command line shell is not zsh, the prefix each of these commands with
#    zsh -fc 'autoload -U zmv && zmv $@'
# take the -n off to make it do the work instead of just talk about it

zmv -Qn '(**/)(*)(.)' '${1}prefix${2}'
zmv -Qn '(**/)(*)(.)' '${1}${2}suffix'
zmv -Qn '(**/)(*)(.)' '${1}${(U)2}'
# without the (.) qualifier (and the enabling -Q), dirs are processed also
zmv -n '(**/)(*)' '${1}prefix${2}'
zmv -n '(**/)(*)' '${1}${2}suffix'
zmv -n '(**/)(*)' '${1}${(U)2}'
share|improve this answer

This rename perl script evaluates the first argument as code to rename the files given with the rest of the arguments.

#!/usr/bin/perl

($op = shift) || die "Usage: $0 perlexpr [filenames]\n";
if (!@ARGV) {
    @ARGV = <STDIN>;
    chop(@ARGV);
}
for (@ARGV) {
    $was = $_;
    eval $op;
    die $@ if $@;
    rename($was,$_) unless $was eq $_;
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.