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'm trying to copy a bunch of files named folder.jpg into a folder. The problem is because all the files are named the same thing, I need to rename them in the process. I know I can probably do it with sed but I'd like to rename them to the name of part of the parent folder. Here is what I got just to find and copy the files

cp $(find . -iname "folder.jpg") .albumart/

The folder structure is ./artist/artist.year.album/folder.jpg and what I'd like to use the parent folder (or just part of it) to name the file. Can someone help me with a one liner to accomplish the task? To make things even trickier, some folders have one more level of CD1 and CD2 that I would like to ignore if they are present (e.g. ./artist/artist.year.album/CD1/folder.jpg)

share|improve this question
add comment

3 Answers 3

up vote 4 down vote accepted

Assuming you have bash, this version simply takes your folder structure (e.g. ./foo/bar/baz/folder.jpg) and replaces all the slashes with underscores (e.g. so you get foo_bar_baz_folder.jpg):

find . -iname folder.jpg -exec bash -c 'for x; do x=${x#./}; cp -i "$x" ".albumart/${x//\//_}"; done' _ {} +

Note that no matter what you do, any time you move files from multiple locations into the same destination, there is always a chance of a name collision.

share|improve this answer
    
I believe this will move the .jpg files rather then copy is that correct? I think I'd just need to replace it with find . -iname folder.jpg -exec bash -c 'for x; do x=${x#./}; cp -i "$x" ".albumart/${x//\//_}"; done' _ {} + correct? –  Rothgar Feb 4 '13 at 21:17
    
@Rothgar Yes, I didn't read carefully enough and assumed you wanted to move. I've changed the mv to cp now. –  jw013 Feb 4 '13 at 21:53
add comment

With zsh:

autoload zmv
zmv -n -C '(**/)folder.jpg' '.albumart/${1:t}.jpg'

Remove -n when happy.

That one will avoid name collisions (will fail with an error if two substitutions resolve to the same name) like:

$ zmv -n -C '(**/)folder.jpg' '.albumart/${1:t}.jpg'
zmv: error(s) in substitution:
b/c/folder.jpg and a/b/c/folder.jpg both map to .albumart/c.jpg
share|improve this answer
    
+1 for zmv. By far the easiest and whitespace-safe-est option for this sort of thing. –  Kevin Feb 4 '13 at 22:20
    
I like the idea. Any way to take out the spaces in the names (replace them with _)? I'm going to have to go find some more documentation on zsh and zmv for future reference. –  Rothgar Feb 4 '13 at 23:01
add comment

Don't parse the output of find. This breaks if there are whitespace or glob characters ?*\[ in file names. If you use find, make it call the command with the -exec action. Call a shell in the -exec action to perform the necessary string transformations.

find -name folder.jpg -exec sh -c '
    dir=${0%/*}      # stip off the file name
    case $dir in */CD[0-9]) dir=${dir%/*};; esac
    cp -ip "$0" ".albumart/${dir##*/}.jpg"
' {} \;

Zsh's zmv is often the easiest way to do this kind of copying.

zmv -C -o-p -w '**/*.jpg' '.albumart/${${${1%/}/CD<->}##*/}.jpg'

Some explanations:

  • The general syntax is zmv OPTIONS… SOURCE_PATTERN REPLACEMENT.
  • -w turns on wildcard group matching. In the replacement text, $1 refers to the part matched by **/ (with a final / unless the matched text is empty, i.e. the file is in the top directory), and $2 to the part matched by * in *.jpg.
  • Both the pattern and the replacement text must be protected against expansion: they need to be passed literally to zmv.
  • To understand ${${${1%/}/CD<->}##*/}, take it from inside out. First take $1. Strip off a final / (if any). Strip off a final pattern matching /CD<->, if any (<-> matches one or more digits). Finally off everything but the last directory component.
  • If you want to replace spaces by underscores, add one more layer of parameter expansion: ${${${${1%/}/CD<->}##*/}// /_}.
share|improve this answer
add comment

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.