How to rename with prefix/suffix?

Viewed 157582

How do I do mv original.filename new.original.filename without retyping the original filename?

I would imagine being able to do something like mv -p=new. original.filename or perhaps mv original.filename new.~ or whatever - but I can't see anything like this after looking at man mv / info mv pages.

Of course, I could write a shell script to do this, but isn't there an existing command/flag for it?

10 Answers

You could use the rename(1) command:

rename 's/(.*)$/new.$1/' original.filename

Edit: If rename isn't available and you have to rename more than one file, shell scripting can really be short and simple for this. For example, to rename all *.jpg to prefix_*.jpg in the current directory:

for filename in *.jpg; do mv "$filename" "prefix_${filename}"; done;

or also, leveraging from Dave Webb's answer and using brace expansion:

for filename in *.jpg; do mv {,prefix_}"$filename"; done;

In Bash and zsh you can do this with Brace Expansion. This simply expands a list of items in braces. For example:

# echo {vanilla,chocolate,strawberry}-ice-cream
vanilla-ice-cream chocolate-ice-cream strawberry-ice-cream

So you can do your rename as follows:

mv {,new.}original.filename

as this expands to:

mv original.filename new.original.filename

I've seen people mention a rename command, but it is not routinely available on Unix systems (as opposed to Linux systems, say, or Cygwin - on both of which, rename is an executable rather than a script). That version of rename has a fairly limited functionality:

rename from to file ...

It replaces the from part of the file names with the to, and the example given in the man page is:

rename foo foo0 foo? foo??

This renames foo1 to foo01, and foo10 to foo010, etc.

I use a Perl script called rename, which I originally dug out from the first edition Camel book, circa 1992, and then extended, to rename files.

#!/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";
    }
}

This allows you to write any Perl substitute or transliterate command to map file names. In the specific example requested, you'd use:

rename 's/^/new./' original.filename

I know there is great answers here but I found no reference to handle filename extensions when adding suffix.

I needed to add '_en' suffix to all wav files in a folder before the file extension.

The magic is here: %.*

for filename in *.wav; do mv $filename ${filename%.*}_en.wav; done;

If you need to handle different file extensions, check this answer. A bit less intuitive.

The easiest way to bulk rename files in directory is:

ls | xargs -I fileName mv fileName fileName.suffix

If it's open to a modification, you could use a suffix instead of a prefix. Then you could use tab-completion to get the original filename and add the suffix.

Otherwise, no this isn't something that is supported by the mv command. A simple shell script could cope though.

I don't like any of the other answers.
My take is that you want a vanilla bash solution. So here you go!

Try this with echo first to see what is going to happen!
Test your command before you use it on thousands of files!

Remove the './' if you want to put in a prefix
find . -type f -exec bash -c 'echo prefix_${0#./}' {} \;

In the question asked, prefix_ is new. so the command becomes
find . -type f -exec bash -c 'echo mv $0 new.${0#./}' {} \;

Remove the extension if you want to put something after it
find . -type f -exec bash -c 'echo ${0%.*}_suffix.${0##*.}' {} \;

Now to use this to rename just replace echo with mv $0.

EXAMPLE:
find . -type f -exec bash -c 'mv $0 1.${0#./}' {} \;

Inspired by: https://gist.github.com/larshaendler/723d2ec447c3c694b71dc6e3bc3aadc9

Related