How can I rename photos, given the EXIF data?

Let’s say I have a bunch of photos, all with correct EXIF information, and the photos are randomly named (because of a problem I had). I have a little program called jhead which gives me the below output:

$ jhead IMG_9563.JPG

File name    : IMG_9563.JPG
File size    : 638908 bytes
File date    : 2011:02:03 20:25:09
Camera make  : Canon
Camera model : Canon PowerShot SX210 IS
Date/Time    : 2011:02:03 20:20:24
Resolution   : 1500 x 2000
Flash used   : Yes (manual)
Focal length :  5.0mm  (35mm equivalent: 29mm)
CCD width    : 6.17mm
Exposure time: 0.0080 s  (1/125)
Aperture     : f/3.1
Focus dist.  : 0.29m
ISO equiv.   : 125
Exposure bias: -1.67
Whitebalance : Manual
Light Source : Daylight
Metering Mode: pattern
Exposure Mode: Manual

Now I need to rename all the photos in the folder in the next format:

001.JPG
002.JPG
003.JPG
...

Where the minor number would be the older image, and the maximum the newer.

I’m not so good scripting, so I’m asking for help.

I think a bash script is enough, but if you feel more comfortable, you can write a python script.

I thought in something like:

$ mv IMG_9563.JPG `jhead IMG_9563.JPG | grep date`

but I don’t know how to do that for all the files at once.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Just found out here that jhead can do it all for you! 🙂

jhead -autorot -nf%Y-%m-%d_%H-%M-%S *.jpg

Method 2

You can to it for all files using a for loop (in the shell/in a shell-script):

for i in *.JPG; do
  j=`jhead "$i" | grep date | sed 's/^File date[^:]+: (.+)$/1/'`.jpg
  echo mv -i "$i" "$j"
done

This is just a very basic outline. Delete echo when you have verified that everything works as expected.

Method 3

exiv2 would be an alternative for manipulating, that allows a very simple syntax:

exiv2 is a program to read and write Exif, IPTC, XMP metadata and image comments and can read many vendor makernote tags. The program optionally con‐
verts between Exif tags, XMP properties and IPTC datasets

So this would rename all jpegs in the current folder:

for i in *.JPG; do exiv2 -v -r '%Y%m%d.%H%M%S.:basename:' rename "$i"; done

If you also want to add geo information, you could use exivtool:

exiftool '-filename<${gpslatitude;} ${gpslongitude} ${datetimeoriginal}' -d "%Y-%m-%d %H.%M.%S%%-c.%%e" *.JPG

Method 4

If someone needs more complex rename, for example to include key exposure values into filename, here is my small script. It renames jpeg files to something like this: NightSky_2014.08.27_22.30.05_NX20_F2.8_f20.0mm_20s_ISO800.jpg.

#!/bin/bash

for s in *.jpg *.JPG
do
 echo $s
 x=`jhead "$s" | 
 awk 'BEGIN { cmt=""; }
/Camera model/   { c=$4$5$6;} 
/Exposure time:/ { e=$3; 
                   if (e==int(e)) e=int(e); 
                   if (e<1) {e=int(0.5+1/e); e="1T" e "s";} else { e=e "s"; } 
                 }
/ISO equiv./     { iso="ISO" $4; } 
/Focal length/   { f="f" $4; } 
/Date.Time /     { d=$3 "_" $4; gsub(":",".",d); }
/Aperture /      { ap=$3; gsub("f/","F",ap); } 
/Comment  /      { cmt=$3 "_"; }
END { print cmt d "_" c "_" ap "_" f "_" e "_" iso ".jpg"; }'`

 echo mv $s $x
 mv $s $x
 echo =====
done

Method 5

I liked the code posted by maxschlepzig but had difficulties with the output nonetheless.

The problem was the space in the resulting filename (between the date string and time string). While trivial for anyone using a GUI, it makes file handling on the command-line somewhat more difficult.

Here the ‘sed’ command has been substantially changed to four separate ‘sed’ operations in favour of the previous monolithic argument. To suit myself, the following also changes the file to normal 644 permissions.

for i in *.JPG ; do
  chmod 644 $i
  j=`jhead "$i" | grep ^Date/Time | sed -e 's/^Date/Time[ ]+: //;s/:/-/g;s/ /_/g':/-/g;s/ /_/g'`.jpg
  echo mv -i "$i" "$j"
  # mv -i "$i" "$j"
done

Method 6

Because it’s easier to deal with (imho), I wrote myself a Ruby script:

require 'fileutils'

ARGV.each { |file|
  if File.exist?(file) && !File.directory?(file)
    exif = `exiftool "#{file}" | grep -E "(Error|Create Date)"`
    if exif.strip.size > 0
      exif = exif.split("n")[0].split(/s+/)
      if exif[0] != "Error"
        # Change the target format here
        filename = exif[3].gsub(":", "-") + " " + 
                   exif[4].gsub(":", ".") + 
                   File.extname(file)
        if filename != file && !File.exist?(filename)
          FileUtils::mv(file, File.dirname(file) + "/" + filename)
        end
      end
    end
  end
}

What does this do?

  1. Iterates over all files passed as parameters (e.g. *.JPG).

    I checked that it handles RAW files and videos correctly. It should work with everything exiftool can deal with.

  2. Does not do anything if a file
    • does not exist,
    • is a directory,
    • does not have an EXIF date, or
    • exiftool reports an error, or
    • a file with the target filename already exists.

That makes it quite robust. In particular, no files can vanish (silently) as is the case with some of the other answers.

Method 7

I like @Kevin’s solution, since I wanted to keep the original name as well (avoiding problem with images taken in the same second), here it is my solution:

for i in *.JPG; do jhead -nf%Y%m%d_%H%M%S_"$(basename "$i" .JPG)" "$i" ; done

Method 8

First posting by newbie… First bash script…
I liked Libor/HalosGhost solution above as it included more details in the rename.
But after testing, duplicate file names would end up losing files.
So I added a counter tag to end of filename for easy reference and collision prevention. I am sure someone here can improve on this but thought it may help.

My apologies posting the code. I am having difficulties with the interface but if someone could point me to correct way of doing things, that would be great.

#!/bin/bash

y=1
for s in *.jpg *.JPG
do
 echo $s
 x=`jhead "$s" | 
 awk 'BEGIN { cmt=""; }
/Camera model/   { c=$4$5$6;}
/Exposure time:/ { e=$3;
                   if (e==int(e)) e=int(e);
                   if (e<1) {e=int(0.5+1/e); e="1T" e "s";} else { e=e "s"; }
                 }
/ISO equiv./     { iso="ISO" $4; }
/Focal length/   { f="f" $4; }
/Date.Time /     { d=$3 "_" $4; gsub(":","",d); }
/Aperture /      { ap=$3; gsub("f/","F",ap); }
/Comment  /      { cmt=$3 "_"; }
END { print cmt d "_" c "_" ap "_" f "_" e "_" iso "_" ; }'`

 echo mv $s "$x${y}.jpg"
 mv $s "$x${y}.jpg"
 y=$((y+1))
 echo =====
done


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x