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?
-
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
exiftoolcan deal with. -
Does not do anything if a file
- does not exist,
- is a directory,
- does not have an EXIF date, or
exiftoolreports 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