I have a folder with two level of subfolders inside it. Inside the second subfolder, there is a jpg file. All the jpg have the same name: cover.jpg



I need to find (and copy to a new folder) all cover.jpg files and rename them adding to its filename (as prefix) the name of the first and second subfolder.

After the intended operation, the content ot /home/user1/newfolder must be:

  • Is there a question here?
    – mikeserv
    Commented May 25, 2014 at 22:26

3 Answers 3


This can be easily achieved the help of sed command. Find the list of files which needs to be renamed and with sed/echo of file path we can achieve the requirement.

cd /home/user
for fl_nm in $(find . -type f -name "cover.jpg")
echo copying the file with desired name to new folder : $fl_nm
cp $fl_nm /home/user1/newfolder/$(echo ${i#*/*} | sed 's/\//_/g')
#Above copy command ignores the find result which extracts only file path from ./**file_path**

All the files with name cover.jpg will be copied to /home/user1/newfolder with the file name with respective folder details in file name.

  • I changed it to cp $fl_nm /home/user1/newfolder/$(echo $fl_nm | sed 's/\//_/g') and it worked! I also removed the first "_" in the file name by adding a new pipe "|" with the sed command.
    – dave
    Commented Jul 18, 2022 at 18:11
#! /bin/bash


for file in folder*/*/*.jpg; do
        echo cp "$file" "${target_dir_path}/${target_file_name}"

Remove the echo if it does what you want.

  • Well, that worked! but I must have done something wrong because I got errors (L1: "filename" comand not found). I cd'ed into the folder in question and did:#! /bin/bash target_dir_path="/home/user/results" for file in folder /*/.jpg; do "$file" # folder001/folderAAA/cover.jpg l1="${file%%/*}" " L1: ${l1}" l2="${file#*/}" l2="${l2%%/*}" " L2: ${l2}" filename="${file##*/}" " filename: ${filename}" target_file_name="${l1}_${l2}_${filename}" cp "$file" "${target_dir_path}/${target_file_name}" done Commented May 25, 2014 at 23:39
  • @user68563 Sorry, I forgot to delete the debug stuff. You should remove the echo only in the cp line. Commented May 25, 2014 at 23:44
  • Thank you! Now it did work perfectly! Just had to remove the word "folder" on line 5: #! /bin/bash target_dir_path="/home/user/results" for file in /*/.jpg; do l1="${file%%/*}" l2="${file#*/}" l2="${l2%%/*}" filename="${file##*/}" target_file_name="${l1}_${l2}_${filename}" cp "$file" "${target_dir_path}/${target_file_name}" done Commented May 25, 2014 at 23:51
  • hey, a strange thing happened on my reply. I wrote: for file in * / * / *.jpg; do (without the spaces, just so it doesn't happen again this time) but i showed only: for file in / * /.jpg; do it can't be my mistake because I pasted my answer from a text file! Commented May 25, 2014 at 23:56
  • sorry for the bad formatting, it was my first question and I don't know yet how to write well in here. I will try to learn soon, though. Regards Commented May 26, 2014 at 0:07

In zsh, put autoload zmv in your .zshrc (or run that one on your command line to experiment with it), then:

mkdir /home/user1/newfolder
zmv '/home/user/(*)/(*)/(cover.jpg)' '/home/user1/newfolder/${1}_${2}_${3}'

Every file that matches the pattern on the left-hand side is renamed to the replacement text on the right-hand side. * means “any sequence of characters”. On the right-hand side, ${1}, ${2} and ${3} are replaced respectively by the portion of the source path matched by the first, second and third parenthesised group in the pattern.

Instead of using explicit grouping, you can request each wildcard to be automatically made a group of its own:

zmv -w '/home/user/*/*/cover.jpg' '/home/user1/newfolder/${1}_${2}_cover.jpg'

Or even:

zmv -W '/home/user/*/*/cover.jpg' '/home/user1/newfolder/*_*_cover.jpg'

Some even go as far as adding:

alias zmmv='noglob zmv -W'

to there ~/.zshrc so as to be able to write:

zmmv /home/user/*/*/cover.jpg /home/user1/newfolder/*_*_cover.jpg

You must log in to answer this question.

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