HiveBrain v1.2.0
Get Started
← Back to all entries
patternbashModerate

Bash script for getting geolocation (latitude, longitude and country code)

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
scriptcountrygeolocationgettingcodeforlatitudeandlongitudebash

Problem

I have a bash script, where I need to get the user's geolocation (latitude, longitude and country code). If a GPS device is present, I use gpspipe. But a lot of laptops/computers don't have GPS devices (yet). I need the location as accurate as possible, and getting the geolocation by IP address is (by far) too unreliable.

I ended up with the following bash script with the following dependencies: Python with sys, urllib and json libraries, wget and a working internet connection.

```
LAT=""
LNG=""
CTRY=""
IFS=$'\n'
printf "Give your location (street name, city, country, etc): "
read LOCATION
while [ -z "$LAT" ]; do
printf "Querying Google Geo API... "
LOCATION=$(echo $LOCATION | python -c "exec(\"import urllib,sys;\\nprint(urllib.quote_plus(sys.stdin.readline()))\")")
URL="https://maps.googleapis.com/maps/api/geocode/json?address=$LOCATION"
GOOGLEAPIS=$(wget -qO- $URL)
STATUS=$(echo $GOOGLEAPIS | python -c "exec(\"import json,sys;\\nobj=json.load(sys.stdin);\\nprint(obj['status'])\")")

case "$STATUS" in
OK)
OPTIONS=($(echo $GOOGLEAPIS | python -c "exec(\"import json,sys;\\nobj=json.load(sys.stdin);\\nfor x in obj['results'][::]:print(x['formatted_address'])\")"))
OPT=$OPTIONS
NRFOUND=${#OPTIONS[@]}
IDX="0"

if [[ $NRFOUND -ge 2 ]]; then
printf "More than one option found. Please select your location from the list:\n"
select OPT in "${OPTIONS[@]}";
do
IDX=$(($REPLY - 1))
break
done
fi
LAT=$(echo $GOOGLEAPIS | python -c "exec(\"import json,sys;\\nobj=json.load(sys.stdin);\\nprint(obj['results'][$IDX]['geometry']['location']['lat'])\")")
LNG=$(echo $GOOGLEAPIS | python -c "exec(\"import json,sys;\\nobj=json.load(sys.stdin);\\nprint(obj['results'][$IDX]['geometry']['location']['lng'])\")")
CTRY=$(echo $GOOGLEAPIS | python -c "exec(\"import json,sys;\\nobj=json.load(sys.stdin);\\nfor x in o

Solution

Bugs:

  • echo "$my_variable" | my_command can behave unexpectedly if the variable starts with one of the echo options. You can do my_command



  • unset $IFS does not unset IFS. For that you need unset IFS.



Simplifications:

  • You shouldn't need to set IFS - read will save the full input to the variable anyway (see help [r]ead).



  • A lot of the code is already Python, and Python has much fewer caveats than Bash, so changing to it would very much benefit the maintainability of the code. Strictly speaking it's not a pure Bash script anyway, and you really don't want to be parsing JSON manually in Bash. If you really need a Bash script (which you shouldn't unless it's for a Bash programming exercise, and even then, somebody is wrong on the Internet if they asked you to use pure Bash to parse JSON) you could make it a wrapper script.



  • Bash's read takes a -p prompt option, so you can avoid the first printf.



  • Unchanging variables such as URL should be assigned outside of the loop.



Style issues:

  • Non-exported variables should be lowercase to distinguish them from exported variables.



  • It is customary to exit` with a non-zero exit code when a command fails.

Context

StackExchange Code Review Q#63855, answer score: 11

Revisions (0)

No revisions yet.