copying files with same name

Erik Trulsson ertr1013 at
Tue Feb 17 07:48:18 PST 2004

On Tue, Feb 17, 2004 at 10:16:18AM -0500, Dru wrote:
> On Mon, 16 Feb 2004, Erik Trulsson wrote:
> > On Mon, Feb 16, 2004 at 04:49:37PM -0500, Dru wrote:
> > >
> > > Okay, I must be missing something obvious here. How do you do a batch copy
> > > while renaming the destination files? I want to copy all of the configure
> > > scripts in /usr/ports to ~/scripts. I can get find to find the files, I
> > > can get sed to rename them, but I can't get the timing down right.
> > >
> > > cp -v `find /usr/ports -name configure -print | sed 's:/:=:g'` .
> > >
> > > renames the files nicely (so they're not all named configure), but does it
> > > too soon--the source no longer exists.
> > >
> > > cp -v `find /usr/ports -name configure -print -exec sed 's:/:=:g' {} \;` .
> > >
> > > gives a syntax error (missing }) and
> > >
> > > cp -v `find /usr/ports -name configure -print | sed 's:/:=:g'` .
> > >
> > > has sed complain of extra characters at the end of a p command, followed
> > > by all my destination files being named configure.
> > >
> > > Is there a way to do this as a one-liner, or does one have to write a
> > > shell script with a while loop?
> >
> > First you should note that there are two ways of using cp(1).
> > The first one is of teh form 'cp src-file dst-file'  and the second one
> > is of the form 'cp src-file1 src-file2 src-file3 ...  dstdir'
> > So if you don't want the dest-file to have the same name as the source,
> > you must invoke cp(1) once for each file.
> >
> > You will have to use some kind of loop to do this. A for loop iterating
> > over the output of find(1) would seem to be better suited for this
> > problem than a while loop.
> Well, I played some more and piping to cpio did the trick. I couldn't do
> it in one go as pass mode doesn't support the interactively rename switch,
> but a temporary copy out followed by an interactive copy in worked.
> I then tried pax -rwi which was even more efficient as it let me rename
> while find was creating the list.

Doing the renaming interactively sounds a bit cumbersome if there are
many files.

The following for-loop ought to do the trick nicely and doesn't require
any interactive actions:
(Assuming you have want to name the destination files as your examples
above indicate, and also assuming you want to copy the files to the
current directory.)

for i in `find /usr/ports -name configure -print`
cp $i ./`echo $i | sed 's:/:=:g'`

You could either put that in a shell-script or type it in directly at
the commandline.  It works with both /bin/sh and zsh, and ought to work
with bash and ksh as well.

The above for-loop is actually  a bit inefficient since it doesn't
start to do any copying until after find has found all the files to be
copied, and this can also give a very long command-line after the
expansion of find's output which might cause trouble.

An better alternative is to do the copying as find(1) goes down the
tree with something like the following one-liner:

find /usr/ports -name configure -exec sh -c 'cp {} `echo {} | sed s:/:=:g`' \;

<Insert your favourite quote here.>
Erik Trulsson
ertr1013 at

More information about the freebsd-questions mailing list