lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

On Wed, Feb 18, 2009 at 04:57:27PM -0800, Florin Andrei wrote:
> Newbie here, I needed a pretext to learn Lua, so I made a script which 
> takes a bunch of image files and sorts them neatly into folders based on 
> the EXIF timestamp of each file.
> Please see the script attached to this message and comment on any mistakes, 
> idiosyncrasies, faux pas, etc.

It's always a joy to code in Lua. The only thing better than to
write code when learning a new language is to read code. So I
rewrote your script, not to make it better but to make it
different, to show other ways in which Lua can work, and
hopefully give some new ideas.

Tables are central in Lua, and a powerful way to handle data, so
you better learn everything there is to know about them. :-)
I've simplified (in my opinion) your script a lot by just using
tables in a different way.


Tommy Pettersson <>

local usage_fmt =
imgsort - script to sort image files based on their EXIF timestamp attributes
by Florin Andrei, 2009/02/18

Usage: %s <directory_containing_pictures>

require 'lfs'

-- cache for speed and convenience
local match, gsub = string.match, string.gsub
local werr = function (...) io.stderr:write(...) end

-- Always require one argument
if table.maxn(arg) ~= 1 then
    werr( string.format( usage_fmt, arg[0] ))
    os.exit( 1 )
local dir = arg[1]

-- Locate exiv2 (the EXIF utility)
local extool do
    local tmp = io.popen( 'which exiv2', 'r' )
    extool = tmp:read()
if not extool then
    werr( 'Cannot find the exiv2 utility. Bye bye.\n' )
    os.exit( 1 )

-- exiv2 outputs lines like:
--   dir/IMG_0373.JPG Image timestamp : 2008:11:07 16:43:50
-- Parse line and insert file path in array with date as key

local dates = {} --:: date => [path]

local excmd = io.popen( extool..' '..dir..'/*', 'r' )
for line in excmd:lines() do
    local name, date = match( line, '^(.+) Image timestamp : ([:%d]+)' )
    if date then
        date = gsub( date, ':', '-' )
        if not dates[date] then dates[date] = {} end
        local names = dates[date]
        names[#names+1] = name

-- Move images to date directories

local split_path_and_filename =
function (name)
    return match( name, '^(.*)/(.*)' ) --=> nil if can't split

for date, names in pairs( dates ) do
    assert( lfs.mkdir( dir..'/' ))
    for _,src in ipairs( names ) do
        local _,filename = split_path_and_filename( src )
        local dst = dir..'/''/'..(filename or src)
        local ok, err = os.rename( src, dst )
        if not ok then
            werr( 'Could not move ',src,' to ',dst,': ',err,'\n' )