5

I've got a simple command that does almost what I want. The following will locate all files with a suffix of '_compressed.swf' and copy each into its same directory with a '.bak2' appended:

find '../content' -name '*_compressed.swf' -print0 | xargs -0 -I {} cp {} {}.bak2

Results
In: /content/somefile_compressed.swf
Out: /content/somefile_compressed.swf.bak2

However, I need to replace '_compressed.swf' with '_content.swf' I'd like to use find, rather than recursive flag on cp for consistency.

Objective
In: /content/somefile_compressed.swf
Out: /content/somefile_content.swf

1

3 Answers 3

6

This solution is probably the most portable:

find "../content" -name "*_compressed.swf" -exec sh -c 'cp {} `dirname {}`/`basename {} compressed.swf`content.swf' \;

There is also the famous rename.pl script which is distributed with Perl, and the rename command which could have made this a bit easier. These aren't available on all distributions though, these commands are for the most part.

6
  • The above moves the files from their current location to the script's location and adds the suffix 'content.swf'. Replacing mv with cp gets me closer, but I still need replace text in name rather than append. I'm getting closer by using sed, but still learning. Feb 23, 2010 at 22:00
  • @Michael you're right! whoops. I was only testing in the current directory hence why it worked for me. I've fixed it :)
    – John T
    Feb 24, 2010 at 4:19
  • Hey, thanks John. I like it. Much of this is all new to me. I understand usage of find, -exec, sh, dirname {}, basename {}, but I'm a little confused about the combined usage. sh -c ' ' converts the string into a command and runs the command, right? mv {} expands into one of find results "mv ../content/file1of20_compressed.swf ???????" It's the second part of that which I don't understand yet. What is causing the compressed.swf to be replaced by content.swf? In my solution you can see I just learned how to use sed. Feb 24, 2010 at 17:53
  • 2
    @Michael what's happening is the file is being moved with a new name. If {} contained /etc/somefile_compressed.swf, dirname takes /etc and basename {} compressed.swf will leave you with somefile_. Now you put these 2 together with the slash I added in the middle (/) and you have /etc/somefile_. You'll notice I added content.swf to the end so it completes the statement as /etc/somefile_content.swf. HTH.
    – John T
    Feb 24, 2010 at 22:54
  • i'd use rename.pl if mv functionality was desired (it's not hard to add to any system with Perl) but the cp makes this a different beast. you'd have to tweak the script to do a copy instead of rename, which would work, but is more work. @John - nice find solution; it's big and long and ugly, but it looks like it would work. (don't ask me to help test it tho!) :) Feb 24, 2010 at 23:45
1

I'm sure this all can be handled in one line. I got really close to a one line solution and with some help even closer, but no success. The following works:

#!/bin/bash

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

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


# Use for loop read all directory names
for (( i=0; i<${FilesIndex}; i++ ));
do
    source="${FilesArray[$i]}"
    destination="$(echo "${source}" | sed 's/compressed/content/')"
    cp "${source}" "${destination}"
done

exit 0;
0

I believe this should do the trick and is collapsible to a one liner if you really really need to ;)

find ../content -name '*_compressed.swf' | while read file
do
cp "$file" "${file/_compressed.swf/_content.swf}"
done

Bash pattern substitution works nicely in these cases.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .