I am trying to move my library of photos (over 12000) out of iPhoto for use in Adobe Lightroom and would like to include the GPS data I've added to the photos using iPhoto's in-app feature (This data is stored in Apple's proprietary database, not as metadata in the photo itself). I can transfer the data by exporting but I want the original RAW files which iPhoto won't modify. So my proposed solution is this:

1) Export all original RAW photos into a directory tree sorted by event name. 2) Export all photos as JPEGs with the GPS data embedded in the EXIF data (as iPhoto can do). 3) Use "exiftool" to pull the GPS data from the jpeg and copy it in to the matching raw file.

I can do #3 one photo at a time with the following command:

exiftool -overwrite_original_in_place -tagsFromFile ~/Photos-Mod/Event001/photo001.jpg -gps:all ~/Photos-Orig/Event001/photo001.NEF

The Photos-Mod files have the GPS data from iPhoto, and Photos-Orig do not. The directory tree and file names will be identical except for the main directory name and the file extension (in some cases, my original is also a jpeg). I'm hoping that there is a good way to make a script that can run exiftool on the iPhoto modified files in the Photos-Mod parent directory, and move the GPS data to the original file of matching file name and event directory in the Photos-Orig parent directory.

I just don't have the scripting skills. Any help here would be hot.

  • This question is a bit too far into the “gimme teh codez plz” region, but I think I can help you solve the problem yourself. First, a few important questions: ① Do you have any programming experience (if yes, of what form)? This helps targeting explanations. ② Can you guarantee the only difference between photo paths is Mod changing to Orig, and the extension changing from jpg to NEF? ③ Is the depth of the photo paths constant, or do some event folders have sub-folders that should be visited? ④ Do you want to use Perl or Bash? – amon Apr 30 '13 at 23:56
  • amon, Totally "gimme teh codez plz" (sorry)but I will take any help you can give in learning how to solve my problem. I have limited experience, just wayyyy out of practice. Matlab mostly and some shell scripting (bash). Used sed and grep a lot for the last. But I am 10 years out of practice. The difference will be Mod to Orig as you said and the extension, but some of the extensions won't change. (some will be .NEF > .jpg, and others will be .jpg > .jpg) The depth will be constant. I organize as Photos-Orig/Year/Event001/photo001.NEF I am most familiar with bash, zero experience with perl. – Ben Gross May 1 '13 at 16:55

The problem consists of the following parts:

  1. Find all photos under the Photos-Mod directory
  2. Find each corresponding photo under Photos-Orig
  3. Invoke exiftools with correct arguments

Finding all photos

This is easy by using a glob expression like ~/Photo-Mod/*/*.

Finding the corresponding photo

Given a full path, we can substitute the Photo-Mod for Photo-Orig. We further change the file extension to * so that we have another glob expression. If this glob matches no files, we print an error message, but simply carry on.

Invoking exiftools is now easy.

A Bash solution

Quick recap of Bash syntax:

  • Foreach-loops:

    for variable in EXPR; do
  • If-else:

    if COND; then
  • Filetests: [ -e $file ] (-e tests for existence of files)

  • variable assignments: var=$(COMMANDS).

We can use regular expressions via sed.

# There are probably more elegant ways, but I don't know much bash
for mod in ~/Photo-Mod/*/*/*; do
  orig=$(echo $mod | sed -e 's/Photo-Mod/Photo-Orig/;s/\.[^.]*$/.*/');
  orig=($orig); # Apply the glob expression, select result
  if [ -e $orig ]; then
    exiftool -overwrite_original_in_place -tagsFromFile "$mod" -gps:all "$orig";
    echo "No corresponding file for $mod found. Skipping!" >&2;

This can be run directly on the commandline by removing all newlines. You can also put it into a shell script., and invoke it from there.

(Note: tested with similar glob expressions and without exiftools under GNU bash)

A Perl solution

Quick introduction to Perl syntax:

  • Foreach-loops:

    for my $variable (LIST) {
  • If-else:

    if (COND) {
    } else {
  • Filetests: -e $filename

  • variable assignments: my $var = EXPR;

Regular expressions are part of the language, and can be applied by $var =~ /REGEX/.

use strict; use warnings; # helps us write better scripts
use autodie; # automatic error handling

for my $mod (glob '~/Photo-Mod/*/*/*') {
  my $orig = $mod;
  $orig =~ s/Photo-Mod/Photo-Orig/;
  $orig =~ s/\.[^.]*$/.*/;
  if (($orig) = glob qq("$orig")) { # implicitly tests for existence
    system 'exiftool', '-overwrite_original_in_place',
      '-tagsFromFile', $mod, '-gps:all', $orig;
  } else {
    warn "No corresponding file for $mod found. Skipping!\n";

You can dump the code in a file, then invoke it with perl script.pl. Or you can use a here-doc:

$ perl <<'END'
# The code goes here

(Note: The Perl scripts were tested with perls v16.3 and v14.2 on Linux.)

  • amon, this looks perfect. Will test and let you know how it goes! Thanks again for your help. – Ben Gross May 2 '13 at 22:18
  • Almost got it with the perl script I think. I am running in to trouble with the white spaces in the Event names (meaning directory names). Is there a way to get around that or do I have to rename everything? – Ben Gross May 4 '13 at 22:28
  • @BenGross Perl's glob function splits the given pattern at whitespace into subpatterns. Putting quotes around the argument should fix that—I updated my code accordingly. I don't have sufficiently deep knowledge of the parsing rules to make the same fix in the bash version. – amon May 4 '13 at 22:37
  • Your perl script works like a charm! Thanks amon. I was trying qq{} in different places in the script, but couldn't get it to work. Thanks again! – Ben Gross May 5 '13 at 16:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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