Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a folder with a number of files in it ABC.* (there are roughly 100 such files). I want to duplicate them all to new files with names starting with DEF.*

So, I want

ABC.Page1
ABC.Page2
ABC.Topic12
...etc

copied to

DEF.Page1
DEF.Page2
DEF.Topic12
...etc

What is the simplest way to do this with a batch command (in BASH or similar)? I am thinking something involving sed or awk or xargs, but I'm having difficulty figuring out the syntax. I could write a Python script, but I'm thinking there is probably a command line solution that is not too complicated.

share|improve this question
    
A venerable mc file manager has a most extensive support for this sort of mass renames. –  oakad Apr 2 at 0:25
    
@oakad tar is no spring-chicken, either. See my answer for an example. –  mikeserv Apr 2 at 10:57

7 Answers 7

up vote 16 down vote accepted

How about something like this in bash:

for file in ABC.*; do cp "$file" "${file/ABC/DEF}";done

you can test it by putting echo in front of the cp command:

for file in ABC.*; do echo cp "$file" "${file/ABC/DEF}";done
share|improve this answer
    
perfect. even simpler than i imagined. –  Octopus Apr 1 at 19:43
    
It'll be good enough in most cases but check with the echo is crucial here. Never do this in a script. For more info read bash pitfalls –  pawel7318 Apr 8 at 0:10

To do this efficiently with a large number of files, it is better to avoid a starting a different cp process for each one. One way would be to copy then rename them using prename (rename is symlinked to this by default on Debian based distros). Using this and the Linux mktemp:

tmp=$(mktemp -d --tmpdir=.)
cp ABC.* "$tmp"
prename "s:$tmp/ABC:DEF:" "$tmp/"*
rmdir "$tmp"

Update

Actually pax may be a better way to go here:

pax -rws '/^ABC/DEF/' ABC.* .

Unfortunately, despite pax being both POSIX and Linux Standard Base, few distros currently include it by default.

share|improve this answer
    
nice touch using the : as the separator to avoid escaping. –  Clayton Stanley Apr 2 at 4:48

You could do this:

for i in ABC.*; do cp {ABC,DEF}."${i#*.}"; done
share|improve this answer
    
Maybe there's something I'm not seeing, but how am I setting multiple destinations? I'm using the for loop to get each. I did test the code beforehand, and it worked as expected, so I would appreciate your explanation. –  Sara Fauzia Apr 2 at 9:11
    
That's my bad, I misread your answer. :-) –  Chris Down Apr 2 at 9:16
    
Thanks for letting me know! –  Sara Fauzia Apr 2 at 9:39

If you don't mind using a less standard tool, I recommend using mmv (mass move) which was written for this very kind of tasks. Using mcp (mass copy), which is part of the suite, you could simply do

mcp "ABC.*" "DEF.#1"

It's not exactly easy to find download packages. The current Debian package (which Arch also uses in AUR) to compile at home can be found here.

share|improve this answer

In zsh, put the following lines in your .zshrc:

autoload -U zmv
alias zmv='noglob zmv'
alias zcp='zmv -C'
alias zln='zmv -L'

Then, on the command line, you can run

zcp 'ABC(.*)' 'DEF$1'

or simply

zcp -W ABC.* DEF.*

In another shell, as long as you have zsh installed:

zsh -c 'autoload zmv; noglob zmv -CW ABC.* DEF.*'
share|improve this answer

tar will do this for you really fast.

TEST

First I created 2 directories and 10 files:

% mkdir test1 test2 ; cd test1
% for n in `seq 1 10` ; do touch ABC.file$n ; done
% ls

> ABC.file1   ABC.file2  ABC.file4  ABC.file6  ABC.file8
> ABC.file10  ABC.file3  ABC.file5  ABC.file7  ABC.file9

Then I copied them:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC/DEF/' -xf -
% ls ../test2

> DEF.file1   DEF.file2  DEF.file4  DEF.file6  DEF.file8
> DEF.file10  DEF.file3  DEF.file5  DEF.file7  DEF.file9

TRANSFORM

So GNU tar will accept a sed --transform=EXPRESSION for file renaming. This can even rename only some of the files. For instance:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC\(.*[0-5]\)/DEF\1/' -xf -
% ls ../test2

> ABC.file6  ABC.file8  DEF.file1   DEF.file2  DEF.file4
> ABC.file7  ABC.file9  DEF.file10  DEF.file3  DEF.file5

So that's one advantage.

STREAM

Also consider that this is only two tar processes - and that will not alter regardless of your file count.

tar | tar

tar is as optimized as you could want it to be. This will never have problem argument counts or runaway child processes. This is just A > B done.

ARGUMENTS

I use 7 distinct arguments combined between my two tar processes here. The most important one is listed here first:

- stdout/stdin - this informs tar that it will be streaming either its input or output to or from stdin/stdout which it will interpret correctly depending on whether or not it is building or extracting an archive.

-c create - this tells tar to build the archive. The next argument tar expects is...

-f file - we specify that tar will be working with a file object rather than a tape-device or whatever. And the file it will be working with, as noted above, is stdin/stdout - in other words, our |pipe.

./* all $PWD/files - not too much to explain here except that the archive argument comes first, so - then ./*.

...and on the other side of the |pipe...

-C change directory - this informs tar that it needs to change to the directory I specify before performing any other action, so effectively it just cd ../test2 before extraction.

--transform='s/ed/EXPR/' - as has already been mentioned, this did the renaming. But the docs indicate that it can take any sed expression or //flag.

-x extract - after tar changes to our target directory and receives our renaming instructions we instruct it to begin extracting all of the files into its current directory from the -f - |pipe archive file. No mystery.

share|improve this answer
1  
Here is the pax solution for this question. I would add it to my answer, but I think it is better suited here - pax -rws '/^ABC/DEF/' ABC.* . –  Graeme Apr 3 at 2:48
    
@Graeme - woah - that's way better! Man, it beats the hell out of pearl rename, too! You should put this in your answer - pax is POSIX specified - hence the pax. –  mikeserv Apr 3 at 4:57
    
pax might be POSIX, but it is rarely installed by default unfortunately. –  Graeme Apr 3 at 11:45

You could do this: http://www.projectik.eu/index.php/programovanie/linux/item/243-linux-kopirovanie-suborov-vo-vlakne Here is example

share|improve this answer
1  
Welcome to Unix & Linux! While this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference. –  terdon Jul 22 at 16:46

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.