Saturday, August 28, 2010

I wrote a program today to organize photos. I have a great number of photos from over the years; they were mostly organized at some time in the past, but got copied wholesale to new hard drives when it was time to migrate, or got stowed in a tarball somewhere, etc... anyway this program i wrote (in perl) will, given a source directory and a target directory, iterate through the source directory finding files matching a given file type (in this version, jpg and cr2, but that can change), extract the creation date from the file's EXIF data, create a directory tree (as needed) under the target path as year/month/day and either move or copy the file into that directory. I'm going to post the code now, but it's not totally mature and it's not yet commented at all. have a gander if you like. I intend to improve this in the future but no promises are made. also i guarantee it not to bug-free.

I'm releasing this under the GPL, v3 which can be found at

#!/usr/bin/perl -w -- call this version 0.01

use strict;
use File::List;
use File::Copy;
use File::Path;
use Image::ExifTool;
use File::Basename;

my $basedir = "put path to source here";
my $target = "put path to target here";
my $i = 0;

my $search = new File::List("$basedir");
my $fileArrRef = $search->find("JPG\$|jpg\$|cr2\$|CR2\$");

sub pathbuild {
    my $newpath = $_[0];
    if (! -d $newpath) {
        if ( -e $newpath ) {
    return $!;

my $dtOrig;my $date;my $time;my $yr;my $mo;my $day;
foreach my $fullname (@$fileArrRef) {
    my $info = Image::ExifTool::ImageInfo($fullname);
    if ($$info{DateTimeOriginal}) {
        $dtOrig = $$info{DateTimeOriginal};
        ($date,$time) = split( / /, $dtOrig);
        ($yr,$mo,$day) = split(/:/, $date);
    } else {
        $dtOrig = '';
    my ($name,$path,$ext) = File::Basename::fileparse($fullname,qr/jpg|cr2/i);
    my $dest = "$target/undated";
    if ($dtOrig) {
        $dest = "$target/$yr/$mo/$day"

    my $destfile = "$dest/$name$ext";
    $i = 0;
    while (-e $destfile){
        $destfile = "$dest/$name$i.$ext";
    if (link ($fullname,$destfile)){
        unlink ($fullname);
    } else {
        copy ($fullname,$destfile);