I'm using darktable 3.6.0 and am still struggling to find a good workflow. I originally started out with a folder structure where my photos were grouped by "event", but this proved limiting. Instead, I want to switch to a folder structure by date, like yyyy/mm/dd/*.CR2.

To use this new structure during import from camera, I'm using gphoto2 from the command line:

gphoto2 --get-all-files --skip-existing --filename '%Y/%m/%d/%f.%C'

Subsequently I import the new photos into darktable. That all works fine.

But how do I convert my existing library to this structure, while preserving the sidecar files (*.XMP) containing my edits and metadata?

I tried to use the new copy & import feature in darktable, again with $(YEAR)/$(MONTH)/$(DAY) folder naming pattern, but this has two problems. One, sidecar files are not imported but instead created anew. And two, everything ends up in a folder with today's date.

Since gphoto2 apparently knows how to read metadata, I tried to use it to import from a folder rather than a camera, but it doesn't seem to have an option for that. (Am I overlooking something?) But in any case, it would probably ignore sidecar files.

I could come up with a shell script using exiftool to read metadata and move files around accordingly, but surely there is a simpler way? In Lightroom this would have been trivial...


1 Answer 1


Here's the shell script I came up with:


set -e


for f in $(find $in_dir -iname \*.cr2 -or -iname \*.jpg | sort); do
  out_dir=$(exiftool -DateTimeOriginal $f | awk '{print $4}' | sed 's#:#/#g')
  mkdir -p $out_dir
  mv -v $f $out_dir/$(basename $f)
  mv -v $f.xmp $out_dir/$(basename $f).xmp || true

rmdir $in_dir

It's invoked one directory at a time, and will crash if it encounters anything unusual. It also doesn't work if there are spaces in any filename. So it's not great, but it solves my problem for now... better answers are still welcome, if not for me, then for the next person who comes along.

  • 1
    \$\begingroup\$ Will be wise to use double quotes around variables when do mkdir and mv. And for xmp file you use variable which is like 123456.cr2 and the result name will be 123456.cr2.xmp \$\endgroup\$ Sep 15, 2021 at 9:06
  • \$\begingroup\$ And about last command rmdir what will happen if you have subdirectories? \$\endgroup\$ Sep 15, 2021 at 9:18
  • \$\begingroup\$ @RomeoNinov I know this is not production-ready code. I just let the script fail on such cases and dealt with them manually. \$\endgroup\$
    – Thomas
    Sep 15, 2021 at 12:19
  • \$\begingroup\$ Thomas, it is always wise to follow some rules (and to have less errors to correct). BTW are the source files in one directory? \$\endgroup\$ Sep 15, 2021 at 12:40
  • \$\begingroup\$ The reason for absence of quoting is that I like to put echo in front of all commands that have side effects, so that I can inspect what will be done. Once I'm satisfied I just pipe the output of the script through sh. That doesn't play nice with quotes unless you're very careful, so I just omitted them, knowing that I don't have spaces in filenames anyway. There were some cases with subdirectories in the source directory, but those are handled fine. Feel free to improve my answer or post one of your own based on this script. \$\endgroup\$
    – Thomas
    Sep 15, 2021 at 12:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.