Home > Blockchain >  BASH: copy only images from directory, not copying folder structure and rename copied files in seque
BASH: copy only images from directory, not copying folder structure and rename copied files in seque

Time:08-26

I have found an old HDD which was used in the family computer back in 2011. There are a lot of images on it which I would love to copy to my computer and print out in a nice photobook as a surprise to my parents and sister.

However, I have a problem: These photos have been taken with older cameras. Which means that I have a lot of photos with names such as: 01, 02, etc. These are now in hunderds of sub-folders.

I have already tried the following command but I still get exceptions where the file cannot be copied because one with the same name already exists.

Example: cp: cannot create regular file 'C:/Users/patri/Desktop/Fotoboek/battery.jpg': File exists

The command I execute:

$ find . -type f -regex '.*\(jpg\|jpeg\|png\|gif\|bmp\|mp4\)' -exec cp --backup=numbered '{}' C:/Users/patri/Desktop/Fotoboek \;

I had hoped that the --backup=numbered would solve my problem. (I thought that it would add either a 0,1,2 etc to the filename if it already exists, which it unfortunately doesn't do successfully).

Is there a way to find only media files such as images and videos like I have above and make it so that every file copied gets renamed to a sequential number? So the first copied image would have the name 0, then the 2nd 1, etc.

CodePudding user response:

** doesn't do successfully ** is not a clear question. If I try your find command on sample directories on my system (Linux Mint 20), it works just fine. It creates files with ~1~, ~2~, ... added to the filename (mind you after the extension).

If you want a quick and dirty solution, you could do:

#!/bin/bash  

counter=1
find sourcedir -type f -print0 | while IFS= read -r -d '' file
do
    filename=$(basename -- "$file")
    extension="${filename##*.}"
    fileonly="${filename%.*}"
    cp "$file" "targetdir/${fileonly}_${counter}.$extension"
    (( counter  = 1 ))
done
  • In this solution the counter is incremented every time a file is copied. The numbers are not sequential for each filename.
  • Yes I know it is an anti-pattern, and not ideal but it works.

If you want a "more evolved" version of the previous, where the numbers are sequential, you could do:

#!/bin/bash

find sourcedir -type f -print0 | while IFS= read -r -d '' file
do
    filename=$(basename -- "$file")
    extension="${filename##*.}"
    fileonly="${filename%.*}"
    counter=1
    while [[ -f "targetdir/${fileonly}_${counter}.$extension" ]]
    do
        (( counter  = 1 ))
    done
    cp "$file" "targetdir/${fileonly}_${counter}.$extension"

done
  • This version increments the counter every time a file is found to exist with that counter. Ex. if you have 3 a.jpg files, they will be named a_1.jpg, a_2.jpg, a_3.jpg
  • Related