The photos of my cameras (.CR2 or .JPG) have correct exif date + time but only in seconds, unfortunately not in milliseconds. Therefore some photos have the same date_time value (shot at the same second). The photos are saved in sub-folders which is why creating unique filenames (beyond all folders) just by date_time is not possible with exiv2. Initial situation example:

Folder 1 / 2016_12_01_1326.JPG
Folder 1 / 2016_12_02_1830.CR2
Folder 2 / 2016_12_01_1326.JPG (same date, hours, and seconds but not milliseconds)

I would like to create symbolic links with unique name for all of my photos. My idea for solving this problem is by converting the filenames of the photos to date-time with exiv4 and the symbolic links with the same name plus an ongoing number.

So finally the result of the symbolic links should be for example:


My approach is the following but it doesn't work with the ongoing number:

export f;
var=0; export var;
find 2016/. \( -name "*.CR2" -o -name "*.JPG" \) -execdir sh -c 'ln -s "$PWD"/$(basename {}) "$f"/2016_Links/Pictures/Link_"$((var++))"_$(basename {})' {} \;

The $((var++)) is not working due to the following error:

./20160312_09_02_42.CR2: 1: ./20160312_09_02_42.CR2: arithmetic expression: expecting primary: "var++"
  • 1
    where is f defined so that it can be referenced with $f? – Zanna Dec 20 '16 at 11:30
  • The specific error arithmetic expression: expecting primary: "var++" is almost certainly because your sh is not bash, and does not support the ((var++)) arithmetic syntax – steeldriver Dec 20 '16 at 13:12
  • Thank you for the hint... I have added f in the code example. – CR500 Dec 20 '16 at 14:29
  • As far as I can remember I also tried $((var=var+1)). Anyway I will try that again in a few hours. – CR500 Dec 20 '16 at 14:30
  • When I try it with $((var=var+1))" every symbolic link is starting with the same Leading Number. var is not increasing. :-( – CR500 Dec 20 '16 at 19:06

The problem in the question is that "var" is is incremented in a subshell started by '-execdir', so the parent shell doesn't get the changed value. In this case you can't use find to do all the work for you since find doesn't track progress.

Here is the solution which includes both the desired link name and the one you almost used in the find command, give it a try and use the one you like.

export var=0
for F in $(find 2016 \( -name "*.CR2" -o -name "*.JPG" \)); do
    echo ln -s "$PWD/${F}" "$PWD/2016_Links/Pictures/${FL%.*}_$(printf "%04d" $((var++))).${FL##*.}"
# or
    echo ln -s "$PWD/${F}" "$PWD/2016_Links/Pictures/Link_$((var++))_${F##*/}"

Edit: In case of names containing spaces, first of all quotes are a must, then a small change to different loop should do the trick:

export var=0
find 2016 \( -name "*.CR2" -o -name "*.JPG" \) | while read F; do
    echo ln -s "$PWD/${F}" "$PWD/2016_Links/Pictures/${FL%.*}_$(printf "%04d" $((var++))).${FL##*.}"
    # or
    echo ln -s "$PWD/${F}" "$PWD/2016_Links/Pictures/Link_$((var++))_${F##*/}"
  • Thank you very much! Almost very good solution. There is only one problem with white spaces in the folders name. The folders name of the sources should be ignored. – CR500 Dec 21 '16 at 22:19

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.