Search code examples
macosterminalfilenamescommand-line-arguments

Parse filenames into touch command on OS X


I have a large number of photos on my machine where I'd like to parse the standard naming convention I have created for each file, and then pipe it to the touch command.

For example, I have these files:

2016-08-06-00h28m34.jpg
2016-08-06-00h28m35.jpg
2016-08-06-00h28m36.jpg

I would like to generate (and then run) the following commands:

touch -t 201608060028.34 2016-08-06-00h28m34.jpg
touch -t 201608060028.35 2016-08-06-00h28m35.jpg
touch -t 201608060028.36 2016-08-06-00h28m36.jpg

I can do this manually in a text editor, but it's extremely time-consuming, due to the number of files in each directory. I could also do it in C# and run it over my LAN, but that seems like overkill. Heck, I can even do this in SQL Server, but ... it's OS X and I'm sure there's a simple command-line thing I'm missing.

I've looked at Windows version of Unix touch command to modify a file's modification date from filename part, and Split Filename Up to Define Variables, but I can't seem to figure out how to add in the period for the seconds portion of the script, plus I don't want to add the batch script to each of the hundreds of folders I have.

Any assistance will be greatly appreciated.


Solution

  • Simple Option

    I presume you are trying to set the filesystem time to match the EXIF capture time of thousands of photos. There is a tool for that, which runs on OSX, Linux (and Windows if you must). It is called jhead and I installed it on OSX using homebrew with:

    brew install jhead
    

    There may be other ways to install it - jhead website.

    Please make a back up before trying this, or try it out on a small subset of your files, as I may have misunderstood your needs!

    Basically the command to set the filesystem timestamp to match the EXIF timestamp on a single file is:

    jhead -ft SomeFile.jpg
    

    So, if you wanted to set the timestamps for all files in $HOME/photos/tmp and all subdirectories, you would do:

    find $HOME/photos/tmp -iname \*.jpg -exec jhead -ft {} \;
    

    Option not requiring any extra software

    Failing that, you could do it with Perl which is installed on OSX by default anyway:

    find . -name \*.jpg | perl -lne 'my $a=$_; s/.*(\d{4})-(\d+)-(\d+)-(\d+)h(\d+)m(\d+).*/$1$2$3$4$5.$6/ && print "touch -t $_\ \"$a\"" '
    

    which gives this sort of output on my machine:

    touch -t 201608060028.34 "./2016-08-06-00h28m34.jpg"
    touch -t 201608060028.35 "./2016-08-06-00h28m35.jpg"
    touch -t 201501060028.35 "./tmp/2015-01-06-00h28m35.jpg"
    

    and if that looks good on your machine, you could send those commands into bash to be executed like this:

    find . -name \*.jpg | perl -lne 'my $a=$_;s/.*(\d{4})-(\d+)-(\d+)-(\d+)h(\d+)m(\d+).*/$1$2$3$4$5.$6/ && print "touch -t $_\ \"$a\"" ' | bash -x
    

    And, for the Perl purists out there, yes, I know Perl could do the touch itself and save invoking a whole touch process per file, but that would require modules and explanation and a heap of other extraneous stuff that is not really necessary for a one-off, or occasional operation.