# Work the Shell - Exploring Lat/Lon with Shell Scripts

in
Never get lost at the command line again.

(The invocation is substitute/old-pattern/new-pattern/.)

Now we've got what we set out to create initially. Let's try it with yet another address:

```\$ sh whereis.sh 1313 S. Disneyland Drive, Anaheim CA
33.814413,-117.924424
```

Yep, that's the parking structure for Disneyland in California.

Distance between Two Points

Now comes the hard part of this, actually. We can get the lat/lon of any address we desire, but calculating the distance between two points is a bit more tricky, as the mathematics involved is rather hairy, because what we're basically going to do is measure relative to the circumference of Earth.

I found a formula in JavaScript on-line as a starting point:

```var R    = 6371;        // kilometers
var dLat = (lat2-lat1);
var dLon = (lon2-lon1);
var a    = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2);
var c    = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d    = R * c;
```

In this case, the circumference is R, and it's 6,371km. Because Earth is an oblate spheroid, not a perfect sphere, I expect this will have some small level of error, but let's proceed and see where we get.

To accomplish any sophisticated mathematics in a Linux shell, we're pretty much stuck with bc, but it's plenty powerful enough for this task, even if it's a bit clunky.

As an example, here's how you'd set the value of pi within a bc script:

```pi=\$(echo "scale=10; 4*a(1)" | bc -l)
```

The first stumble we have is that bc wants to work with radians, not degrees, but the lat/lon values we're getting are in degrees, so we need to convert them.

But before we do that, here's the intermediate output we seek, as we now need to work with two addresses, not just one:

```\$ sh farapart.sh \
"1600 pennsylvania ave, washington dc" \
"1313 s. disneyland drive, anaheim, ca"

Lat/long for 1600 pennsylvania ave, washington dc

= 38.89859, -77.035971

Lat/long for 1313 s. disneyland drive, anaheim, ca

= 33.814413, -117.924424
```

Next month, we'll crack open the script to see how I am working with two addresses at the same time and splitting it into the four variables we'll later need. Then, we'll look at how to use bc to do the math.

Dave Taylor has been involved with UNIX since he first logged in to the on-line network in 1980. That means that, yes, he's coming up to the 30-year mark now. You can find him just about everywhere on-line, but start here: www.DaveTaylorOnline.com. In addition to all his other projects, Dave is now a film critic. You can read his reviews at www.DaveOnFilm.com.

______________________

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.

## Comment viewing options

### 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')"
sed -e 's/.*{\("Lat":[^}]*\).*/\1/' -e 's/"L.."://g'
exit 0
```

Here 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:

```args='?appid=onestep&qt=1&id=m&qs="
```

You've got a string with mismatched quotes: it starts with a single quote and ends with a double quote, you need this:

```args='?appid=onestep&qt=1&id=m&qs='
#                                 ^
```

or this

```args="?appid=onestep&qt=1&id=m&qs="
#    ^
```

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:

```  curl -s "\$CONVERTER\$ADDR" | \
```

to

```  curl -s "\$converter\$addr" | \
```

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.

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.

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')"

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.

Webcast
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers

Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.