13

I often import photos and videos (mostly having JPG and MOV extensions) from digital cameras and tablets to my PC, and I would ideally like to see them sorted according to the dates and times they were taken already present in their EXIF data. And hence my wish to rename them all preferably using a simple Nautilus Script by preferably inserting the date and time stamps before each filename.

I have so far managed only to bring together the following Nautilus Script, which I believe is far from perfect:

for i in *.*
do
mv -i "$i" "$(exiftool -CreateDate "$i" | awk -F ': ' '{print $2}')_"$i"" 
done

What I don't like in this renaming method is the colons used in EXIF date and time stamps (e.g. "2013:09:03 20:55:09_IMG_0108.JPG") which might create problems when transferring these files later to other environments (e.g. Windows).

This command (using exiv2 instead of exiftool) conveniently enables manipulation of date and time stamps but its drawback is that it doesn't work on video (e.g. MOV) files:

exiv2 -k -r '%Y-%m-%d_%H-%M-%S_:basename:' rename "$i"

So I'm hoping someone can come up with a better solution. And it would be magic if it even managed to convert the original filenames and extensions to lowercase as well!

Zanna
  • 70,465
Sadi
  • 10,996
  • In addition to the great answers below you should also check out pyRenamer. I have no experience using it with video files, (do they have EXIF data?) but I can say it is excellent for photos. It can change file extensions to lowercase as well. – Tom Brossman Oct 07 '13 at 16:48

5 Answers5

16

I needed to rename my photos and found this question here -- I just found out that exiftool handles it natively:

From http://www.sno.phy.queensu.ca/~phil/exiftool/filename.html

exiftool -d %Y-%m-%d_%H-%M-%S%%-c.%%e "-filename<CreateDate" DIR 

If you want to keep track of original filename and write extension lower case:

exiftool -d %Y%m%d_%H%M%S%%-c-%%f.%%le "-filename<DateTimeOriginal" [.|DIR]

The same works also with the whole filename in lowercase:

exiftool -d %Y%m%d_%H%M%S%%-c-%%lf.%%le "-filename<DateTimeOriginal" [.|DIR]
MadMike
  • 4,244
  • 8
  • 28
  • 50
DerekC
  • 171
  • DIR must be the Folder where the Photos are allocated. If we have already opened a Terminal in the Folder where we want to execute the Command, we have to replace DIR for . And if you want to add a Prefix, to the Filename (i.e. IMG_) this must be inserted before the date chain without any quote. Here an example:

    exiftool -d IMG_%Y%m%d_%H%M%S%%-c.%%e "-filename<CreateDate" .

    – Nothor Apr 15 '17 at 08:05
7

What I don't like in this renaming method is the colons used in EXIF date and time stamps (e.g. "2013:09:03 20:55:09_IMG_0108.JPG") which might create problems when transferring these files later to other environments (e.g. Windows).

You could run the naming scheme through sed, to replace the colons with dashes and spaces with underscores, like so:

mv -i "$i" "$(exiftool -CreateDate "$i" | awk -F ': ' '{print $2}' | sed -e 's/:/-/g' -e 's/ /_/g')_$i"

As for making the whole thing lowercase, you could use rename:

rename 's/(.*)/\L$1/' file.JPG
##  or
rename 's/(.*)/\L$1/' *.*

Or you could do it within your script using sed, as in:

j=$(echo "$i" | sed -e 's/\(.*\)/\L\1/')

...and then use the $j variable in place of the final $i of your mv line. This sed way is slightly more portable (if that matters to you) as different linux distros have different rename commands, while sed is universal.

Or, alternatively, the script can be modified as follows to perform filename conversion to lowercase at the beginning using tr instead:

for arg 
do
  tmp="$(echo "$arg" | tr '[A-Z]' '[a-z]')"
  mv -i "$arg" "$(exiftool -CreateDate "$arg" | awk -F ': ' '{print $2}' | sed -e 's/:/-/g' -e 's/ /_/g')_$tmp"
done

To perform slightly different commands for different file types, a bash case statement can be used in this script. For example:

#! /usr/bin/env bash
for filename in ./*
do
  tmp="$(echo "$filename" | tr '[A-Z]' '[a-z]')"
  case "$filename" in
    *.MOV|*.mov) 
      mv -i "$filename" "$(exiftool -a -s -CreateDate-tur "$filename" | awk -F ': ' '{print $2}' | sed -e 's/\-[0-9][0-9]\:00//g' -e 's/\+[0-9][0-9]\:00//g' -e 's/:/-/g' -e 's/ /_/g')_$tmp"
      ;;
    *.JPG|*.jpg)
      mv -i "$filename" "$(exiftool -a -s -CreateDate "$filename" | awk -F ': ' '{print $2}' | sed -e 's/:/-/g' -e 's/ /_/g')_"$tmp""
      ;;
    *)
      echo 'Not a *.jpg or a *.mov!'
      ;;
  esac
done

In this example, renaming of MOV files that have CreateDate timestamps ANY NUMBER of hours AFTER OR BEFORE JPG files is adjusted by using another (-tur) EXIF data and removing that that time difference suffix, and it might be necessary to change -tur part according to the location set in the system.

evilsoup
  • 4,485
  • Unfortunately I couldn't figure out how to convert filenames to lowercase as you suggest (inserting that line above and changing the last $i to $j didn't do anything). Instead, I inserted filename conversion to lowercase at the beginning and took the liberty of adding this as another option (which worked at least for me) to the end of your answer so that I can accept your answer. Of course you can edit your answer further as you wish. – Sadi Sep 16 '13 at 06:09
  • @sadi looking at it with fresh eyes, I can see what I was doing wrong with the sed command. The latest version will work, though of course if the tr method works for you that's fine (I have a sneaking suspicion that the tr solution might be slightly more efficient actually, though the sed one will handle non-English characters better) – evilsoup Sep 16 '13 at 08:53
  • Thank you. I wonder if you can also help me further improve this script by using one command for MOV files and another for others along the lines: if [the extension is MOV] blah blah; else blah blah. The reason is that I've just realized "CreateDate" stamp in my MOV files (from iPad) are strangely have +4 hours and I need to use another option (CreateDate-tur) for them to achieve an accurate order of photos and videos. – Sadi Sep 16 '13 at 09:49
  • The best way for that (in my opinion) is to use a case statement; here's something to get you started. You can also use an if statement, but case statements can be more easily expanded for extra file extensions. Search the internet for 'bash case statement' for more information. – evilsoup Sep 16 '13 at 10:01
  • Thanks a million!!! I'll also add this option to the answer, if you don't mind. – Sadi Sep 16 '13 at 10:54
  • I'm sure I've seen a comment on the internet along the lines of 'if you're using sed and awk with exiftool, you're probably not appreciating the full power of the program', so I'm sure there's a more elegant way of doing all this. I've never had to use exiftool on more than the most basic level though (to provide information for vifm's previews), so I have no idea how to do that. – evilsoup Sep 16 '13 at 11:58
3

I'd use krename for this. It

  • shows live preview
  • allows undo
  • can go recursively into dir
  • allows multiple rename patterns
  • allows globs and regexps in patterns
  • remembers history
Adobe
  • 3,891
2

I know you said that you preferred a script, however, if you are open to a free Java application you can use AmoK Exif Sorter

enter image description here

opticyclic
  • 701
  • 6
  • 24
0

pyRenamer will not work on my new installed Ubuntu 16.04, therefore I have to find another way to solve this problem too.

I have files such as IMG_0001.JPG, IMG_0002.JPG,... in one folder.

I found this question on Stack Overflow useful.

Install "exiv2" first. I used it as follows:

for img in $(ls \*.[Jj][Pp][Gg] 2> /dev/null); 
  do exiv2 -r'%Y%m%d_%H%M%S_'"$(tmp=${img%%.\*}
  echo ${tmp##*_})" rename "$img"
done

The output filenames are YYYYMMDD_HHMMSS_0001.JPG, YYYYMMDD_HHMMSS_0002.JPG,... etc. Even where the photos were taken at the same second, the original photo serial number will make the difference.

Zanna
  • 70,465
chuck lee
  • 56
  • 4