0

I have a parent directory with thousands of directories within sub-directories and so on. In some of the sub-directories I have few image files.

I want to copy (rsync is preferred) all of the bmp and jpg files from the sub-directories to a single new directory without any sub-directories. But at the same time I want to append the name of the LAST directory where the file comes from to the copied file.

├── example1
│   ├── fdfd
│   │   ├── db_files
│   │   │   ├── asdasd.zip
│   │   │   ├── dfdfsta.zip
│   │   │   ├── csf_4545.zip
│   │   │   ├── 45455.zip
│   │   │   ├── 4544.zip
│   │   │   ├── 45545.zip
│   │   │   ├── gfdfgd.zip
│   │   │   ├── retert.zip
│   │   │   ├── vcxvxc.zip
│   │   │   ├── vcxcvcx.zip
│   │   │   ├── asdr3.zip
│   │   │   ├── tetst.zip
│   │   │   ├── testeh.bmp
│   │   │   └── testst43.zip
│   │   ├── TEST_FILE.bmp
│   │   └── hfexport.csv
│   └── testFOLDER2018-05
│       ├── Databasef.txt
│       ├── Folder_Backup_2014-01-05.7z
│       ├── full_Export.pdf
│       ├── f-to-7000.csv
│       ├── f-to-505.csv
│       ├── f-to-600.csv
│       ├── f-to-960.bmp
│       ├── g-to-1000.jpg
│       └── 7000.csv
├── example3
│   ├── img_copy
│   │   ├── automation
│   │   │   ├── f.sh
│   │   │   ├── fff.sh
│   │   │   └── test.bat
│   │   ├── all.bmp
│   │   ├── h23.txt
│   │   ├── old2_copy.jpg

In the example above, the copied files will be as follows:

db_files_testeh.bmp
fdfd_TEST_FILE.bmp
testFOLDER2018-05_f-to-960.bmp
testFOLDER2018-05_g-to-1000.jpg
img_copy_all.bmp
img_copy_old2_copy.jpg

How can I achieve this?

I use the following commands to copy only bmp and jpg files to a new directory.

find -regex '.*\.\(bmp\|jpg\)' | tee /home/tmp/matches.txt
while read -r LINE; do rsync -vh --append-verify --chmod=ugo=rwX --progress --stats "$LINE" /mnt/storage3/backups/NEW_DIR/ONLY_IMAGES; done < /home/tmp/matches.txt
0
find . -type f '(' -name '*.bmp' -o -name '*.jpg' ')' -exec sh -c '
    for pathname do
        newname="${pathname%/*}_${pathname##*/}"  # a/b/c/d.bmp --> a/b/c_d.bmp
        newname="target/${newname##*/}"           # a/b/c_d.bmp --> target/c_d.bmp

        printf "Would move %s to %s\n" "$pathname" "$newname"
        # mv -i "$pathname" "$newname"
    done' sh {} +

This finds all regular files whose filenames end with either .jpg or .bmp. For batches of these files, a short shell script is executed.

The shell script extracts the directory pathname of each file, along with its filename and concatenates the two with an underscore in-between. This forms the new name. The new name is then trimmed of it's initial directories, leaving only the filename, and a target directory path is appended to this.

The final mv is commented out for safety. Run this once with it commented out to see that it does the correct thing.

Related:

  • Great answer. It works exactly as I wanted. I believe replace the mv section with rsync "$pathname" "$newname" should not pose any problems, correct? – zirodec Aug 1 '18 at 12:46
  • At least when I put rsync --dry-run "$pathname" "$newname" in place of mv, I do not recognize any suspicious behavior. – zirodec Aug 1 '18 at 12:47
  • @zirodec That should be okay to do, yes. I forgot that you wanted to use rsync. – Kusalananda Aug 1 '18 at 13:04
  • @zirodec But keep in mind that you can have name clashes if two files have the same name but reside in different directories, and those parent directories too can have same names if there parents' name differ. – Rakesh Sharma Aug 1 '18 at 18:01

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.