At the moment I have a set of files of the form of:

/dir one/a picture.jpg
/dir two/some picture.jpg

What I want to do is copy and change the end to -fanart.jpg to the filename to:

/dir one/a picture.jpg
        /a picture-fanart.jpg
/dir two/some picture.jpg
        /some picture-fanart.jpg

I've managed to get it working for the situation where there are no spaces:

% for i in `find . -name "*.jpg"`; do cp $i "${i%.*}"-fanart.jpg ;done;

but I to get it working where there are spaces.


Command substitution (`...` or $(...)) is split on newline, tab and space character (not only newline), and filename generation (globbing) is performed on each word resulting of that splitting. That's the split+glob operator. You could improve things by setting $IFS to newline and disable globbing, but here, best is to write it the proper way:

find . -name "*.jpg" -type f -exec sh -c '
  for i do
    cp "$i" "${i%.*}-fanart.jpg"
  done' sh {} +

You could also use pax for that:

pax -rws'/\.jpg$/-fanart&/' -s'/.*//' . .

Or zsh's zmv:

autoload zmv
zmv -QC '(**/)(*)(.jpg)(D.)' '$1$2-fanart$3'

Word expansion is performed during the expansion of unquoted command substitutions, which is why this does not work.

If you have bash4+, just use globstar:

shopt -s globstar
for file in **/*.jpg; do
    cp -- "$file" "${file%.*}-fanart.jpg"
  • That assumes there is no symlink to directories in there. If you're going to use **/ best is to use zsh or ksh93 which don't have the problem. – Stéphane Chazelas Jan 21 '14 at 7:14
  • @StephaneChazelas Traversing symlinks to directories is not universally undesirable (although I agree, it is not ideal in many situations). I am still pushing for there to be an option to disable recursion in 4.3. – Chris Down Jan 21 '14 at 7:51
  • I agree make **/ not follow (like in zsh, ksh93 or tcsh) and make the "following symlinks" an option would be better. However, options a la shglob are nice but sometimes add more issues than they solve. It's better to enable the unexpected behaviour per-glob than globally. Using ***/ like in zsh or tcsh would be better. Having globbing qualifiers to enable the noglob, nullglob, nocaseglob, failglob... per-glob like in zsh would also be a lot better. – Stéphane Chazelas Jan 21 '14 at 10:30
  • @StephaneChazelas Considering how long bash 4 has been out now, I highly doubt that Chet would be willing to break backwards compatibility. *** would be reasonable, otherwise. – Chris Down Jan 21 '14 at 10:43
  • Chet has done far worse backwards compatibility breaking before (for instance to align =~ with ksh93's). Changing **/ is more likely to fix scripts than break them. GNU grep has broken a (decade long) backward compatibility by making -r stop follow symlinks at some point. – Stéphane Chazelas Jan 21 '14 at 11:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.