How can I use sed to alter the results of find and pass the results to cp?

5

2

In solaris, I'd like to copy all files found by the find command to a slightly different path. The following script basically executes cp for each file found by find. For example:

cp ./content/english/activity1_compressed.swf ./content/spanish/activity1_compressed.swf
cp ./content/english/activity2_compressed.swf ./content/spanish/activity2_compressed.swf
...

#!/bin/bash

# Read all file names into an array
FilesArray=($(find "." -name "*_compressed.swf"))

# Get length of an array
FilesIndex=${#FilesArray[@]}

# Copy each file from english to spanish folder
# Ex: cp ./english/activity_compressed.swf ./spanish/activity_compressed.swf
for (( i=0; i<${FilesIndex}; i++ ));
do
    source="${FilesArray[$i]}"

    # Replace "english" with "spanish" in path  
    destination="$(echo "${source}" | sed 's/english/spanish/')"

    cp "${source}" "${destination}"
done

exit 0;

It seems like a bit much and I wonder how to use sed in-line with the find and cp commands to achieve the same thing. I would have hoped for something like the following, but apparently parentheses aren't acceptable method of changing order of operation:

find . -name *_compressed -exec cp {} (echo '{}' | sed 's/english/spanish/')

Michael Prescott

Posted 2010-03-02T04:18:54.373

Reputation: 3 351

1+1 for using $() instead of backticks. – Paused until further notice. – 2010-03-02T10:18:01.007

Answers

7

There are easier ways, but for portability sake we can use a bit of forking and backticks:

find . -name *_compressed -exec sh -c 'cp {} `echo {} | sed 's/english/spanish/'`' \;

John T

Posted 2010-03-02T04:18:54.373

Reputation: 149 037

Great! +1 The shell maniac! :D Can you give me some hints about the easier ways you was referring at? Maybe those ways will also accomplish better to that purpose. – dag729 – 2010-03-02T04:53:54.477

2I'm not sure on his exact environment, but if all of the files are only within 1 directory, he could cd there then just cp *_compressed.swf ../spanish – John T – 2010-03-02T04:58:03.140

i was thinking the same but instead of 'cding' there he can just give it to 'cp' as the target directory. – akira – 2010-03-02T06:14:50.117

When I make a test run on OS X, -exec sh -c 'cp {} ... works, but if I run on solaris... replacing cp with echo for safety. Output is "{}" I'm guessing that -exec sh -c doesn't work on solaris. – Michael Prescott – 2010-03-02T18:12:34.900

@John T: All of the files aren't in 1 directory. – Michael Prescott – 2010-03-02T18:13:46.300

@Michael that's why I said I wasn't sure on your environment. I made the answer with Linux and OSX in mind, solaris wasn't part of the question. – John T – 2010-03-02T18:18:28.507

@John T: Added environment to question. :) Thanks for introducing me to the -exec sh -c the other day. I've found other good usage for it, regardless of the solaris work. – Michael Prescott – 2010-03-02T18:28:41.757

Try -exec bash -c – John T – 2010-03-02T18:36:55.977

That doesn't work either. I'm working on several tasks and trying different approaches I found that the following works on OSX and not on solaris, giving error about unexpected ( for the first parentheses: for FILE in ./content/english/reading/reading_comprehension/*_content_opt.swf; do echo mv $FILE $(echo $FILE | sed -e 's/_content_opt.swf/_compressed.swf/'); done

Old bash? – Michael Prescott – 2010-03-02T19:08:57.487

Or take a look at the extraordinary super-cow's powers of zsh – dag729 – 2010-03-15T21:07:30.013

1

I'd use the backtick: you'll find more upon it here (backtick is at chapter 3.4.5).

Basically when you enclose a command between backticks the command itself will be substituted in his output.

dag729

Posted 2010-03-02T04:18:54.373

Reputation: 1 894

1$(COMMAND) and COMMAND result in the same output. – akira – 2010-03-02T06:13:43.333