I need to convert to a specific format some gps coordinates which are the output of the exif information of a picture.

This is the typical output:

exif:GPSLatitude: 10/1, 10/1, 10/1
exif:GPSLatitudeRef: N
exif:GPSLongitude: 10/1, 10/1, 10/1
exif:GPSLongitudeRef: E

and this is the string I need to obtain:

10 10 10N 10 10 10E

I have been able to do so with the following script:

cat $somefile | sed "s/    /$nul/g" | sed "s/exif:GPSLatitudeRef: /$nul/g" | sed "s/exif:GPSLongitude:/$nul/g" | sed "s/exif:GPSLongitudeRef: /$nul/g" | sed "s/exif:GPSLatitude: /$nul/g" | sed "s/\/1/$nul/g" | sed "s/,/$nul/g" | tr -d '\n'

However I realised that some pictures have a slightly different output like this:

exif:GPSLatitude: 10/1, 10/1, 1099/100
exif:GPSLatitudeRef: N
exif:GPSLongitude: 10/1, 10/1, 1088/100
exif:GPSLongitudeRef: E

I understood that the /1, /10 and /100 (perhaps a /1000 as well) are denominators of the number before.

Given the following considerations:

  1. I don't need a huge accuracy, therefore I can afford to loose the last two decimals of the last number (ie: 1088/100 can become 10 instead of 10.88);
  2. I would like to have that accuracy;
  3. I am not totally sure that also the first two numbers of the coordinates (degrees and minutes, ie: 10/1 10/1) can have decimals. In this case, the accuracy of the coordinates would be totally messed up pointing to a different place in the world.

How can I modify that script (and maybe make it a bit more elegant) to make the calculations and actually substitute a fraction by a number with a point?


It is very complex to do this with sed. A more suitable tool is awk or bc. For example, to use bc add another sed to convert the input to a sequence of expressions (10/1) and strings (" ") separated by ";" or newline resulting in the following input for bc:

10/1;" "; 10/1;" "; 1099/100
"N \n"
10/1;" "; 10/1;" "; 1088/100
"E \n"

bc will evaluate each expression, and the output will be 10.00 10.00 10.99N 10.00 10.00 10.88E as you wanted. Here's the sed|bc|tr you need:

sed '1i\
/Ref: /s/.$/"& \n"/
s/.*: //
s/,/;" ";/g
' | 
bc | tr -d '\n'

Alternatively, using awk you can replace all your sed and tr commands with just this:

awk '
NF==4 { for(i=2;i<=4;i++){
         printf "%s%g",i==2?"":" ",x[1]/x[2]
NF==2 { printf "%s%s",$2,$1~/Lat/?" ":"\n" }'

This looks for lines with 4 fields (separated by whitespace) and for fields 2 to 4 splits the field $i (say "1099/100") into 2 parts at the "/" character. It then prints part 1 divided by part 2 (x[1]/x[2]) using the %g general format for numbers. The %s in the printf is replaced by nothing for field 2, and by a space for the other 2 fields. This separates the numbers in the output.

For lines with 2 fields (NF==2) it prints the 2nd field ($2) and if field 1 contains the pattern "Lat" it prints a space, else a newline.

| improve this answer | |
  • Incredible. I went for the awk option as it produces a more clean output (I just found out that degrees and minutes cannot have decimals), only seconds can. – giovi321 Jun 12 '16 at 10:56

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.