4

So I'm trying to recursively search folder, and as you might imagine it will be the "Photos"-folder in MacOS.

And in the process, I would like to change the file name, why you might ask? Because Nextcloud is for some reason changing the image name to year-month-day hour-minute-second $(increment number). So I need to be able to define this starting increment number.

This is what I have so far:

# Lets say that starting increment number should be I=7398
# name="$(stat -f '%Sm' -t '%y-%m-%d %H-%M-%S' "$file").$(ls "$file"|cut -d . -f2)"
# echo $name
find . -type f -iname '*.jpg' -size +500k -exec sh -c '
    for file in "$@"; do
        folder="/path/to/backup/folder/$(stat -f '%Sm' -t '%Y/%m' "$file")"
        echo mkdir -p "$folder"
        echo cp "$file" "$folder"
    done
' sh {} +

This works perfect! But I would like to in the process change the name from the files EXIF data, to be '%y-%m-%d %H-%M-%S {increment number}'.ext, 18-08-15 18-32-29 3453.JPG or whatever it is. Is this possible?

This above script reads a JPG, creates directory of the year the file image was created, created another folder corresponding to the month, copies the file to that year folder.

Expected result: also change name '%y-%m-%d %H-%M-%S {increment number}'.ext

  • I don't understand what you mean, where should/could I get that data from if not the EXIF? – Adam Jun 30 at 17:13
  • Thanks but not helpful. Example: I have file names DSC_0001.JPG up, it was snapped 2018-01-22 at 13:00:22, I want to move that file to folder ~/backup/2018/01 and rename it to 2018-01-22 13-00-22.JPG $(increment). (in this example it is one file, but I have around 30k? – Adam Jun 30 at 17:20
  • Thats what Im trying to figure out – Adam Jun 30 at 17:21
  • Adam, I've updated my answer, so you should have a second look as the changes made are better than the original code. – user3439894 Jul 1 at 13:54
3

The following is a proof of concept to show how I'd build out the target_directory and target_filename from the source_filename, based on information in your OP and comments:

$ ls -1
DSC_0008.JPG
DSC_0034.JPG
DSC_0077.JPG
DSC_0132.JPG
codetest

$ cat codetest
#!/bin/bash

find . -type f -iname '*.jpg' -size +500k -exec sh -c '
i=7398
for f in "$@"; do
    m="$(exiftool -d "%Y-%m-%d %H-%M-%S" -FileModifyDate -s -S "$f")"
    d="/path/to/backup/directory/${m:0:4}/${m:5:+2}"
    echo mkdir -p "$d"
    echo cp "$f" "$d/$m $i.${f##*.}"
    ((i++))
done
' sh {} +

$ ./codetest
mkdir -p /path/to/backup/directory/2018/11
cp ./DSC_0008.JPG /path/to/backup/directory/2018/11/2018-11-26 15-39-09 7398.JPG
mkdir -p /path/to/backup/directory/2018/12
cp ./DSC_0034.JPG /path/to/backup/directory/2018/12/2018-12-26 11-52-30 7399.JPG
mkdir -p /path/to/backup/directory/2019/03
cp ./DSC_0077.JPG /path/to/backup/directory/2019/03/2019-03-02 08-36-07 7400.JPG
mkdir -p /path/to/backup/directory/2019/04
cp ./DSC_0132.JPG /path/to/backup/directory/2019/04/2019-04-03 23-42-36 7401.JPG
$ 

Obviously with the echo command in place, the output shown is not quoted and would fail if that was the actual command executed while copying; however, with the echo command removed, the actual executed command has quotes around the arguments and would not fail because of the spaces in the target_filenames.


Using stat instead of exiftool:

#!/bin/bash

find . -type f -iname '*.jpg' -size +500k -exec sh -c '
i=7398
for f in "$@"; do
    m="$(stat -f "%Sm" -t "%Y-%m-%d %H-%M-%S" "$f")"
    d="/path/to/backup/directory/${m:0:4}/${m:5:+2}"
    echo mkdir -p "$d"
    echo cp "$f" "$d/$m $i.${f##*.}"
    ((i++))
done
' sh {} +

Note: Both of these worked when run as either a script, or, sans the shebang, copied and pasted into Terminal. That said, I'm not sure I'd run this on 30K files all at once without adding some error handling as appropriate for what this code will do. I'll leave that up to you to decide how, or if, you want to implement any error handling in the example code shown.

  • 1
    Looking good! I get the expected result, thanks for your time and effort – Adam Jul 1 at 8:11
  • 1
    Two suggestions: for m - exiftool -d '%Y-%m-%d %H-%M-%S' -FileModifyDate -s -S FILE and for d - exiftool -d '%Y/%m' -FileModifyDate -s -S FILE. Now the challenge, this could all be written in exiftool. – fd0 Jul 1 at 9:16
  • 1
    @fd0, Thanks, I incorporated exiftool -d "%Y-%m-%d %H-%M-%S" -FileModifyDate -s -S "$f" into m="$(...)" but did not use exiftool for d, as I did not want to call exiftool a second time. Instead, I chose to replace $(tr '-' '/' <<<"${m:0:7}") with ${m:0:4}/${m:5:+2}, which eliminated the use of tr, and parameter expansion of an already existing variable is much faster and less overhead then calling exiftool a second time. As to, "Now the challenge, this could all be written in exiftool", that would be very interesting; however, I'll leave that up to you to do. 🙂 – user3439894 Jul 1 at 13:52
  • 1
    @nohillside, Thanks for your input, it at least made me find an alternate solution using exiftool without awk; however, I've incorporated part of the suggestion made by fd0, which was better then my original and subsequent exiftool usage. I also got rid of what really was an unnecessary call to tr as well, with a rewrite of the whole answer too. – user3439894 Jul 1 at 14:00

You must log in to answer this question.

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