Work the Shell - Exploring Lat/Lon with Shell Scripts
With the rise of geolocation systems on mobile devices (think “around me” on the Apple iPhone), a consistent method of measuring points on Earth has become quite important. The standard that's used is latitude and longitude, which measure the distance north or south of the equator and the distance east or west of the prime meridian (which goes through Greenwich, England). Your GPS devices all understand this notation, as does Google Maps, Yahoo Maps, MapQuest and so on.
From a shell scripting perspective, we're interested in both being able to identify lat/lon for a point on the Earth and then, armed with that information, to see if we can calculate the distance between two points on the planet.
The first seems almost insurmountably hard until you learn that Yahoo Maps has a very simple API that lets you specify a URL that includes a street address and returns an XML object that includes its lat/lon values.
For example, you might be familiar with 1600 Pennsylvania Avenue, Washington, DC. I know you've seen pictures of the place. What's its lat/lon?
$ u='http://api.maps.yahoo.com/ajax/geocode'
$ a='?appid=onestep&qt=1&id=m&qs=1600+pennsylvania+ave+washington+dc'
$ curl "$u$a"
YGeoCode.getMap({"GeoID" : "m",
"GeoAddress" : "1600 pennsylvania ave washington dc",
"GeoPoint" : {"Lat" : 38.89859,
"Lon" : -77.035971},
"GeoMID" : false,
"success" : 1} ,1);
<!-- xm6.maps.re3.yahoo.com uncompressed/chunked
Tue Aug 4 12:16:51 PDT 2009 -->
Note that the output actually comes back as two lines; the the data above, and in the other examples, has been reformatted to make it more readable.
Skim that return object, and you'll see Latitude = 38.89859 and Longitude = -77.035971. Feed those two into Google Maps as “38.89859,-77.035971” as a check, and you'll find the image shown in Figure 1.
You guessed it, it's the street address of the White House.
Let's start by creating a simple script where you can specify a street address and it will output lat/lon values.
The first part is easy: take whatever was specified on the command line, and “recode” it to be URL-friendly. Then, append that to the Yahoo API URL, and output the results of a curl call:
#!/bin/sh url='http://api.maps.yahoo.com/ajax/geocode' args='?appid=onestep&qt=1&id=m&qs=' converter="$url$args" addr="$(echo $* | sed 's/ /+/g')" curl -s "$converter$addr" exit 0
Let's test it with a different address this time:
$ sh whereis.sh 2001 Blake Street, Denver, CO
YGeoCode.getMap({"GeoID" : "m",
"GeoAddress" : "2001 Blake Street, Denver, CO",
"GeoPoint" : {"Lat" : 39.754386,
"Lon" : -104.994261},
"GeoMID" : false,
"success" : 1}, 1);
<!-- x1.maps.sp1.yahoo.com uncompressed/chunked
Tue Aug 4 12:37:44 PDT 2009 -->
You can figure out what's at this address if you like. More important, you can see that this simple four-line script does the job—sort of.
What we really want, however, is to extract just the lat and lon values and toss everything else out. This can be done with a bunch of different tools, of course, including Perl and awk, but I'm a rebel, so I use cut instead.
To do this, we need to count the double quotes (") in the output block. The 12th double quote is immediately before the latitude value, and the 15th is immediately after the longitude value. If we just worked with that, we would get:
$ sh whereis.sh 2001 Blake Street, Denver, CO | cut -d\" -f13-15 :39.754386,"Lon":-104.994261},
Okay, so that's most of the work. Better, though, is to specify two different specific fields (13,15 rather than 13-15):
$ sh whereis.sh 2001 Blake Street, Denver, CO | cut -d\" -f13,15 :39.754386,":-104.994261},
That's 99% of what we want. Now we just need to clean up the noise. To do that, I'll jump back into the script itself, rather than experimenting on the command line:
curl -s "$converter$addr" | \
cut -d\" -f13,15 | \
sed 's/[^0-9\.\,\-]//g'
And testing:
$ sh whereis.sh 2001 Blake Street, Denver, CO 39.754386,104.994261,
Almost. Really, really close. But, that last comma is not wanted. Hmmm....
Okay! To delete the last comma, we simply need to add a second substitution to the sed statement, so that the full sed expression is now:
sed 's/[^0-9\.\,\-]//g;s/,$//'
Dave Taylor has been hacking shell scripts for over thirty years. Really. He's the author of the popular "Wicked Cool Shell Scripts" and can be found on Twitter as @DaveTaylor and more generally at www.DaveTaylorOnline.com.
Today’s modular x86 servers are compute-centric, designed as a least common denominator to support a wide range of IT workloads. Those generic, virtualized IT workloads have much different resource optimization requirements than hyperscale and cloud applications. They have resulted in a “one size fits all” enterprise IT architecture that is not optimized for a specific set of IT workloads, and especially not emerging hyperscale workloads, such as web applications, big data, and object storage. In this report, you will learn how shifting the focus from traditional compute-centric IT architectures to an innovative disaggregated fabric-based architecture can optimize and scale your data center.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
| Trying to Tame the Tablet | May 08, 2013 |
| Dart: a New Web Programming Experience | May 07, 2013 |
- New Products
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Home, My Backup Data Center
- RSS Feeds
- New Products
- Trying to Tame the Tablet
- What's the tweeting protocol?
- Dart: a New Web Programming Experience
- Reply to comment | Linux Journal
6 min 16 sec ago - Drupal is an Awesome CMS and a Crappy development framework
4 hours 45 min ago - IT industry leaders
7 hours 7 min ago - Reply to comment | Linux Journal
23 hours 56 min ago - Reply to comment | Linux Journal
1 day 2 hours ago - Reply to comment | Linux Journal
1 day 3 hours ago - great post
1 day 4 hours ago - Google Docs
1 day 4 hours ago - Reply to comment | Linux Journal
1 day 9 hours ago - Reply to comment | Linux Journal
1 day 10 hours ago
Enter to Win an Adafruit Prototyping Pi Plate Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Prototyping Pi Plate Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- Next winner announced on 5-21-13!
Free Webinar: Linux Backup and Recovery
Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.
In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.





Comments
error?
When I run this script I get:
whereis: 7: Syntax error: Unterminated quoted string
Here is the script as I have it:
#!/bin/sh url='http://api.maps.yahoo.com/ajax/geocode' args='?appid=onestep&qt=1&id=m&qs=" converter="$url$args" addr="$(echo $* | sed 's/ /+/g')" curl -s "$CONVERTER$ADDR" | \ sed -e 's/.*{\("Lat":[^}]*\).*/\1/' -e 's/"L.."://g' exit 0Here is the command I'm running:
sh whereis 2001 Blake Street, Denver, CO
This seems pretty simple but I cannot see what I'm missing.
Cupla Problems
You've got a couple problems in your script, the one that's giving you the error is here:
You've got a string with mismatched quotes: it starts with a single quote and ends with a double quote, you need this:
or this
The other problem is that the shell is case sensitive, so you can't use "converter" and "CONVERTER" interchangeably, pick one. Same with "addr" and "ADDR". So change:
to
p.s. The first error (the mismatched quotes) was in the original text, it has now been fixed.
Mitch Frazier is an Associate Editor for Linux Journal.
What about bad addresses?
Is there any way to tell if the address you input is invalid? I've tried a few made-up bad addresses and it still seems to give valid lat/lon coordinates.
bad address
That's a "Feature" of yahoo's service. They'll give you their best estimate. If the house number is bad, they'll tell you the location of the street; if the street is bad, they'll tell you the location of the city; if the city is bad, they'll tell you the location of the state....
To tell if the address is bad you could, perhaps, compare the results with the results of a less specific look up.
shell errors
As written, I get only longitude.
when I change the sed to...
cut -d\" -f11,13 | \
I get the expected output
$ cat whereis.sh
#!/bin/bash
URL='http://api.maps.yahoo.com/ajax/geocode'
ARGS='?appid=onestep&qt=1&d=m&qs='
CONVERTER="$URL$ARGS"
ADDR="$(echo $* | sed 's/ /+/g')"
curl -s "$CONVERTER$ADDR" | \
cut -d\" -f11,13 | \
sed 's/[^0-9\.\,\-]//g;s/,$//'
exit 0
$ ./whereis.sh 1313 S Disneyland Drive, Anaheim, CA
33.814413,-117.924424
Response Is Different
The response you're getting is different, the GeoID value is not a quoted value as above. The following would avoid problems related to quotes:
curl -s "$CONVERTER$ADDR" | \ sed -e 's/.*{\("Lat":[^}]*\).*/\1/' -e 's/"L.."://g'Mitch Frazier is an Associate Editor for Linux Journal.