5

I am using a bash command, gps location, that returns a date, time and location information.

[john@hostname :~/develp] $ gps location
Location: {"date": "16/07/20", "time": "19:01:22", "latitude": "34.321", "longitude": "133.453", "altitude": "30m"}

I want to write the longitude to a file, before I get there I need to correctly parse the string.

[john@hostname :~/develp] $ variable=`gps location | awk '/"longitude":/ {print $9}'`
[john@hostname :~/develp] $ echo $variable
"133.453",
[john@hostname :~/develp] $

Currently, awk isn't searching for longitude, it solely is taking the whole string and finding the 9th string. Ideally, I would like to use a regex/keyword approach and find longitude and then the next string after. I have tried using grep | cut also tried sed. No luck, best I can do is using awk.

Beaker
  • 67

7 Answers7

12

Strip off the Location: and you're left with JSON:

$ echo '{"date": "16/07/20", "time": "19:01:22", "latitude": "34.321", "longitude": "133.453", "altitude": "30m"}' |
    jq .longitude
"133.453"

See in the man page if gps has an option to not print the Location: keyword up front, if not stripping it is easy, e.g.:

$ echo 'Location: {"date": "16/07/20", "time": "19:01:22", "latitude": "34.321", "longitude": "133.453", "altitude": "30m"}' |
    cut -d':' -f2- | jq .longitude
"133.453"

or:

$ echo 'Location: {"date": "16/07/20", "time": "19:01:22", "latitude": "34.321", "longitude": "133.453", "altitude": "30m"}' |
    sed 's/Location://' | jq .longitude
"133.453"
Ed Morton
  • 31,617
5

Unfortunately I don't have enough reputation to leave comments, but to expand upon Ed Morton's answer: if you call jq with the -r option, it will automatically strip quotes when the output is just a string (as it is in your case):

$ echo 'Location: {"date": "16/07/20", "time": "19:01:22", "latitude": "34.321", "longitude": "133.453", "altitude": "30m"}' | cut -d':' -f2- | jq -r .longitude
133.453
2

If you want to try this without jq (e.g. because it is unavailable), and the output is always a one-liner as implied by your example, the following sed approach would also work:

sed -r 's/.*"longitude": "([^"]+)".*/\1/'

This will

  • look for a string enclosed in double-quotes ( "([^"]+)", i.e. starting " followed by a string containing "anything but "" until the closing "), where the enclosed content is defined as "capture group" ( ... ), that occurs immediately after a string "longitude":
  • and replace basically the entire line with the content of the capture group (\1) - in your case, the actual value of the longitude

Test:

~$ echo 'Location: {"date": "16/07/20", "time": "19:01:22", "latitude": "34.321", "longitude": "133.453", "altitude": "30m"}' | sed -r 's/.*"longitude": "([^"]+)".*/\1/'
133.453
AdminBee
  • 22,803
1

You can extract the substring using bash builtins, specifically by using only parameter substitutions:

v=$(gps location)
v1=${v#*\"longitude\":\ \"}
echo "${v1%%\"*}"

Wherein we remove everything upto longitude": " in the variable v starting from left. Then in the next step we remove everything upto the last " starting from right. What remains are the longitudinal coordinates.

0

if you can't install jq, you can do it in pure bash using a loop over cut.

i=1
words=$(gps location)
word=$(echo $words | cut -d',' -f$i)
while ( [ -n "$word" ] )
  do
  echo $word | grep longitude | cut -d' ' -f2
  (( i+=1 ))
  word=$(echo $words | cut -d',' -f$i)
done
  • Welcome to the site, and thank you for your contribution. May I recommend that you always quote shell variables and command substitutions unless you know exactly that you don't want it (e.g. because you need word splitting by the shell)? – AdminBee Jul 17 '20 at 11:48
  • That'll be extremely slow and buggy. See why-is-using-a-shell-loop-to-process-text-considered-bad-practice and copy/paste your script into http://shellcheck.net to see some of the issues. – Ed Morton Jul 17 '20 at 16:15
  • Thanks @AdminBee. I didn't know that. I was looking for something similar on a high performance computer cluster running scientific linux. Even the most basic awk things (like print) kept failing, so I had to go and either pipe everything through a c++ program or use pure bash. Might be slow, but can't see why buggy. – Michael Bölting Jul 20 '20 at 06:31
0

Some ideas:

grep -o longitude.:.* < in | grep -o '[0-9.]*' | head -1

grep -o longitude.:.* < in | cut -f3 -d'"'

People often forget the humble tr:

grep -o longitude.:.* < in | tr -dc 0-9., | cut -f1 -d,

or even better:

tr -dc ' La-z0-9.' < in | grep -o longitude.[0-9.]* | cut -f2 -d' '

That last one will make more sense if you realise that the first step produces

Location date 160720 time 190122 latitude 34.321 longitude 133.453 altitude 30m

which as you can see removes a lot of the distraction :-)

0

Done with below awk command and it worked fine

cat filename

Location: {"date": "16/07/20", "time": "19:01:22", "latitude": "34.321", "longitude": "133.453", "altitude": "30m"}

command

awk '{for(i=1;i<=NF;i++){if($i ~ /latitude/){print $(i+1)}}}' filename

output

"34.321"

Python

#!/usr/bin/python
a="""Location: {"date": "16/07/20", "time": "19:01:22", "latitude": "34.321", "longitude": "133.453", "altitude": "30m"}"""

b=a.split(":") for i in range(0,len(b),1): if "longitude" in b[i]: print b[i+1].split(",")[0]

output

 "133.453"