views:

1760

answers:

6

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?

A: 

Do you want to apply it to a whole directory? In that case, you can try

mv * new.*

Ikke
I know the question doesn't say Unix as such, but your answer won't work in Unix. Shells handle wildcards, not the programs themselves.
Chris Jester-Young
No, I only want a single file... or occasionally two files, but not needed it for a whole directory before.Chris: This is for primarily Linux, but I didn't want to specify as I'd like a general solution.
Peter Boughton
+1  A: 

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.

workmad3
Often I want both, but primarily the prefix - as you say, tab completion can handle suffixes.
Peter Boughton
A: 

I vote for the tab completion.

And in case others show up ... KSH uses ESC \ for the same thing.

AIX does not have rename.

jim
What does tab completion have to do with renaming files?
Jonathan Leffler
because you let the tab complete function save you typing. the op wasn't clear on one file or many and if s/he wanted to script it.
jim
+1  A: 

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;
Simon Lehmann
+6  A: 

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
Dave Webb
Thanks, this looks to be the best solution - also works with ksh.
Peter Boughton
What this does not do is work with wild cards. That is, in a directory containing filenames a, b, c, using "echo {,new.}*" yields the list "a b c new.*" (because file name generation via brace expansion occurs before expanding wild card characters - at least by inference).
Jonathan Leffler
+2  A: 

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
Jonathan Leffler
Thanks, if I could accept a second answer this would be it.I wanted a standard command as something that will just work on anything I might use, but I can put this script on the machines I do use frequently and it will still be helpful.
Peter Boughton