Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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:


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.

share|improve this question
I don't understand the minor/maximum sentence and the preceding example. Could you clarify this? –  maxschlepzig Feb 6 '11 at 22:47
That minor/maximum file names is one step up. Because, once I have the files named in a way they represent which is older and newer, I can easily rename to 001.jpg, 002.jpg, etc with another program, although it'd be better to do that with another script. –  Tomas Feb 6 '11 at 23:01
The "renaming table" would be ls *.JPG | wc > rename And then I'd have to use a script rename to XXX.JPG –  Tomas Feb 6 '11 at 23:03
Sory, is not wc, I forgot the one to order by name. –  Tomas Feb 6 '11 at 23:07
The command is sort. –  Tomas Feb 8 '11 at 1:06

4 Answers 4

up vote 6 down vote accepted

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"

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

share|improve this answer
Thanks. Now, grep woudl give me File date : 2011:02:03 20:25:09. How can I filter only the second column? –  Tomas Feb 6 '11 at 22:27
So I only rename the file as 20:25:09 –  Tomas Feb 6 '11 at 22:36
@Tomas, updated the answer - if you really only want the time (what about collisions then?) you have to modify the regular expression, of course. –  maxschlepzig Feb 6 '11 at 22:45
j=`jhead "$i" | grep date | sed 's/.* //'`.jpg instead? –  frabjous Feb 6 '11 at 22:45
@maxshlepzig: Thanks, you missed a ' before ``.jpg` –  Tomas Feb 6 '11 at 22:50

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

jhead -autorot -nf%Y-%m-%d_%H-%M-%S *.jpg
share|improve this answer
Yes! But be careful of that particular format-string, because it'll give two files taken in the same second the same name. %i (or %03i, specifically) will give a sequence number, as requested in the original question. Combining both might not be a bad idea. –  mattdm Mar 21 '11 at 17:21

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.


for s in *.jpg *.JPG
 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 =====
share|improve this answer

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"
share|improve this answer
Welcome to Stack Exchange.  (1) I understand sed pretty well, so I basically understand what you are trying to do.  But our goal at Stack Exchange is not to hand out fish sandwiches or write thousands of one-off solutions to trivially distinct questions; our goal is to teach people how to fish (i.e., teach people, including the current questioner and future readers, how to solve their own problems).  To that end, your answer would be better if you explained what you are endeavoring.  (Please do not respond in comments; edit your answer to make it clearer.)  … (Cont’d) –  G-Man May 31 at 22:08
(Cont’d) …  (2) Your command fails because the quotes aren’t balanced.  Please do not post untested code. –  G-Man May 31 at 22:08

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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