0

The US Naval Observatory has an API that outputs a JSON file containing the sunrise and sunset times, among other things, as documented here.

Here is an example of the output JSON file:

{
"error":false,
"apiversion":"2.0.0",
"year":2017,
"month":6,
"day":10,
"dayofweek":"Saturday",
"datechanged":false,
"lon":130.000000,
"lat":30.000000,
"tz":0,

"sundata":[
            {"phen":"U", "time":"03:19"},
            {"phen":"S", "time":"10:21"},
            {"phen":"EC", "time":"10:48"},
            {"phen":"BC", "time":"19:51"},
            {"phen":"R", "time":"20:18"}],

"moondata":[
            {"phen":"R", "time":"10:49"},
            {"phen":"U", "time":"16:13"},
            {"phen":"S", "time":"21:36"}],

"prevsundata":[
            {"phen":"BC","time":"19:51"},
            {"phen":"R","time":"20:18"}],

"closestphase":{"phase":"Full Moon","date":"June 9, 2017","time":"13:09"},
"fracillum":"99%",
"curphase":"Waning Gibbous"
}

I'm relatively new to using JSON, but I understand that everything in square brackets after "sundata" is a JSON array (please correct me if I'm wrong). So I searched for instructions on how to get a value from a JSON array, without success.

I have downloaded the file to my system using:

wget -O usno.json "http://api.usno.navy.mil/rstt/oneday?ID=iOnTheSk&date=today&tz=0&coords=30,130"

I need to extract the time (in HH:MM format) from this line:

    {"phen":"S", "time":"10:21"},

...and then use it to create a variable (that I will later write to a separate file).

I would prefer to use Bash if possible, preferably using a JSON parser (such as jq) if it'll be easier to understand/implement. I'd rather not use Python (which was suggested by a lot of the articles I have read previously) if possible as I am trying to become more familiar with Bash specifically.

I have examined a lot of different webpages, including answers on Stack Overflow, but none of them have specifically covered an array line with two key/value pairs per line (they've only explained how to do it with only one pair per line, which isn't what the above file structure has, sadly).

Specifically, I have read these articles, but they did not solve my particular problem:

Thanks in advance for any thoughts.

Side note: I have managed to do this with a complex 150-odd line script made up of "sed"s, "grep"s, "awk"s, and whatnot, but obviously if there's a one-liner JSON-native solution that's more elegant, I'd prefer to use that as I need to minimise power usage wherever possible (it's being run on a battery-powered device). (Side-note to the side-note: the script was so long because I need to do it for each line in the JSON file, not just the "S" value)

ZPMMaker
  • 120
  • 2
  • 15
  • You don't want to parse JSON (or most formats with nested structures for that matter) as a plain text or with regex. Save yourself a lot of trouble and get [`jq`](https://stedolan.github.io/jq/). – zwer Jun 10 '17 at 11:34
  • @zwer, I have jq, as suggested by the articles in the links toward the end of my question. Your answer doesn't help me solve the problem. Could you give specifics on how to actually use it for this purpose please? – ZPMMaker Jun 10 '17 at 11:37

2 Answers2

4

If you already have jq you can easily select your desired time with:

sun_time=$(jq '.sundata[] | select(.phen == "S").time' usno.json)
echo $sun_time
# "10:21"
chepner
  • 497,756
  • 71
  • 530
  • 681
zwer
  • 24,943
  • 3
  • 48
  • 66
0

If you must use "regular" bash commands (really, use jq):

wget -O - "http://api.usno.navy.mil/rstt/oneday?ID=iOnTheSk&date=today&tz=0&coords=30,130" \
    | sed -n '/^"sundata":/,/}],$/p' \
    | sed -n -e '/"phen":"S"/{s/^.*"time":"//'\;s/...$//\;p} 

Example:

$ wget -O - "http://api.usno.navy.mil/rstt/oneday?ID=iOnTheSk&date=today&tz=0&coords=30,130" | sed -n '/^"sundata":/,/}],$/p' | sed -n -e '/"phen":"S"/{s/^.*"time":"//'\;s/...$//\;p} 
--2017-06-10 08:02:46--  http://api.usno.navy.mil/rstt/oneday?ID=iOnTheSk&date=today&tz=0&coords=30,130
Resolving api.usno.navy.mil (api.usno.navy.mil)... 199.211.133.93
Connecting to api.usno.navy.mil (api.usno.navy.mil)|199.211.133.93|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [application/json]
Saving to: ‘STDOUT’

-                            [ <=>                              ]     753  --.-KB/s    in 0s      

2017-06-10 08:02:47 (42.6 MB/s) - written to stdout [753]

10:21
Jack
  • 5,801
  • 1
  • 15
  • 20