Following
Robert Seale’s advice, I was looking for a solution to batch rename photo files. After my last shoot I used digikam and while the results were as desired, it took a second or more per image, which I thought a bit long. After not finding a different suitable solution I asked
the question on unix.stackexchange and was overwhelmed by two people’s in-depth answers. I learned a lot from both
mikserv and
Gilles and in the end settled with Gilles’ suggestion. I take zero credit for the solution, I don’t even understand parts of what is going on, but I amended it a little bit nonetheless and thought the extended version might help someone.*
Preliminaries
What I get when I come home is file names looking like this: _DSC1234.NEF. What I wanted instead was
- date-shot in YYYYMMDD-format plus
- a descriptive shoot-name plus
- image-number
looking like this: 20140708_WeddingAdamAndEve_0001.NEF
There are a few issues with this:
ad 1. Date Shot: sometimes I can only copy and rename the files a few days after shooting, so the date should reflect the date the picture was taken, not the date it was copied. Getting date-shot from the file itself is difficult as there is no birth time recorded. The closest is mtime which is the time the file’s content has last been modified. However, creation date is stored in image file’s EXIF data.
ad 2: Name of Shoot: Ideally I wanted this to be a variable I could set as a parameter when calling the script.
ad 3. Number of Image: This should reflect the age of the image with the oldest one having the lowest number. The problem is that cameras usually restart numbering at 0000 once they hit 9999. So images n-9999 can potentially be older than 0000-n. I needed a solution that would cater for this special case.
The code
# original solution by @Gilles (http://unix.stackexchange.com/questions/141138/)
# set base path and navigate to "basepath + parameter 1"
BASEPATH='/media/data/photo/';
cd $BASEPATH$1
# add "EXIF creation time" as prefix to original file names
exiv2 mv -r %Y%m%d-%H%M%S:basename: *.NEF
# Now we have files with names like 20140630-235958_DSC1234.NEF.
# final rename
i=10000
for x in *.NEF; do
i=$((i+1))
mv "$x" "${x%-*}_$2-${i#1}_Copyright-Jan-Soehlke.NEF"
done
Walkthrough
Line 4: Here we set our base path. We choose the highest directory ever useed to store pictures.
Line 5: Navigate to base path + parameter 1. If our script is called rename and the pictures are in /media/data/photo/weddings/adam+eve, then we call the script through
./rename weddings/adam+eve
Line 8: In a first iteration we add EXIF-creation time as a prefix to the original file names. We use exiv2 for this operation. -r is for rename and we use YYYYMMDD-hhmmss, which is %Y%m%d-%H%M%S in strftime(3), plus :basename: to keep the original filename after the time stamp.
Through creation time as a prefix we now sort files by age, even if the files would sort differently by name. This could happen if during a shoot we reach 9999 and the camera’s counter continues at 0000 or if we shot with two different cameras.
By also retaining the original file name for now, we make sure that in case there are multiple files with the same time stamp, they still have individual names. EXIF time’s finest unit is a second, so if we fire bursts of images (Nikon’s D4s for example shoots at 11 frames/second), we have multiple files with the same creation date and thus potentially 11 files with the same name.
Line 12: The counter variable i counts from 10000 and is used with the leading 1 digit stripped; this is a trick to get the leading zeros so that all counter values have the same number. If you want more (or less) than four digits, set i accordingly.
Line 15: ${x%-*} removes everything that follows the - character, in our case it is hours, minutes and seconds as well as the original filename. ${i#1} writes the new four digit file number.
$2 provides a second variable, which we use for the shoot name. In this case we want it to be WeddingAdamAndEve, so we call the script through
./rename weddings/adam+eve WeddingAdamAndEve
Finally, I added _Copyright-Jan-Soehlke. It not only reminds someone who downloads the file that it is indeed copyrighted, it also helps with SEO as my name is automatically associated with each image I upload.
Possible Problems
a) The original file names already have a -
in place. In this case change the - in line 8 to something different (like _) and use the same character in the ${x%-*}-part in line 15 (in this case ${x%_*}, otherwise the script will not work as intended.
b) A burst of images reaches across the 9999
/0000
-mark. These specific files will not be in order after renaming – but they weren’t in order in the first place, so I have no idea how to tackle this rare scenario other than by setting your camera’s counter to reset to 0000 after each formatting.
c) Your files do not contain EXIF data. In this case see mikeserv’s solution which uses a different angle of attack and is thoroughly and well explained.
___________________________
* Stackexchange uses the CC-BY-SA license, so all the code in this example is naturally also CC-BY-SA.