【问题标题】:Defining a variable from a value in a JSON array in Bash在 Bash 中从 JSON 数组中的值定义变量
【发布时间】:2017-06-10 11:19:14
【问题描述】:

美国海军天文台有一个 API,可输出包含日出和日落时间等内容的 JSON 文件,如 here 所记录的那样。

输出 JSON 文件的Here is an example

{
"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"
}

我对使用 JSON 比较陌生,但我知道“sundata”之后方括号中的所有内容都是 JSON 数组(如果我错了,请纠正我)。所以我搜索了有关如何从 JSON 数组中获取值的说明,但没有成功。

我已使用以下方式将文件下载到我的系统:

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

我需要从这一行提取时间(HH:MM 格式):

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

...然后用它来创建一个变量(我稍后会写入一个单独的文件)。

如果可能的话,我更喜欢使用 Bash,如果它更容易理解/实现,最好使用 JSON 解析器(例如 jq)。如果可能的话,我宁愿不使用 Python(我之前读过的很多文章都建议使用 Python),因为我正试图更加熟悉 Bash。

我检查了很多不同的网页,包括 Stack Overflow 上的答案,但没有一个专门涵盖每行有两个键/值对的数组行(他们只解释了如何只用一对每行,遗憾的是,这不是上述文件结构所具有的)。

具体来说,我已经阅读了这些文章,但它们并没有解决我的特定问题:

提前感谢您的任何想法。

旁注:我已经设法使用由“sed”、“grep”、“awk”等组成的复杂的 150 多行脚本来做到这一点,但显然如果有单行 JSON - 更优雅的原生解决方案,我更喜欢使用它,因为我需要尽可能减少电力使用(它在电池供电的设备上运行)。 (旁注的旁注:脚本很长,因为我需要为 JSON 文件中的每一行执行此操作,而不仅仅是“S”值)

【问题讨论】:

  • 您不想将 JSON(或大多数具有嵌套结构的格式)解析为纯文本或正则表达式。为自己省去很多麻烦并获得jq
  • @zwer,我有 jq,正如我的问题末尾链接中的文章所建议的那样。你的回答并不能帮助我解决问题。您能否详细说明如何将其用于此目的?

标签: arrays json bash


【解决方案1】:

如果您已经拥有jq,您可以通过以下方式轻松选择所需时间:

sun_time=$(jq '.sundata[] | select(.phen == "S").time' usno.json)
echo $sun_time
# "10:21"

【讨论】:

  • 太棒了;效果很好。谢谢你的帮助。 :)
【解决方案2】:

如果你必须使用“常规”bash 命令(真的,使用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} 

例子:

$ 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

【讨论】:

    猜你喜欢
    • 2014-04-19
    • 2014-04-21
    • 1970-01-01
    • 1970-01-01
    • 2015-03-28
    • 1970-01-01
    • 2021-04-17
    • 2018-06-15
    • 2015-05-14
    相关资源
    最近更新 更多