【问题标题】:Loop through json variable循环通过 json 变量
【发布时间】:2019-08-28 15:49:35
【问题描述】:

我有一个如下所示的 json 变量:

{
  "status": "closed",
  "host": "host1-availabe_zone_A"
}
{
  "status": "closed",
  "host": "host2-availabe_zone_B"
}
{
  "status": "closed",
  "host": "host3-availabe_zone_A"
}

我正在尝试将其转换为类似哈希的数据结构(zsh/bash 中的关联数组)以获取每个可用区域中的主机数。首选结果将是基于上述数据的结果:

availabe_zone_A -> 2
availabe_zone_B -> 1

我在尝试迭代 json 变量时遇到了一些问题。

declare -A az_to_number_of_open_hosts
for host in $(jq . <<<  $hosts_list)
do
  az=$(rev <<< $(echo $host | jq .host) | cut -d. -f3 | rev)
  ((az_to_number_of_open_hosts[$az]++))
done

提取可用区域的行是因为主机格式始终为blabla123213.az.domain.com。 该代码不起作用,因为变量 host 似乎是指每行 json 字符串而不是 json 条目。有没有推荐的方法来迭代每个 json 条目?

【问题讨论】:

  • 这不是有效的 JSON。如果您有多个对象,则它们必须包含在一个数组中,以便您可以循环遍历它。
  • 您希望jq . 做什么?它只是将输入作为输出返回。
  • 为什么声明az_to_number_of_open_hosts而不使用它?
  • @Barmar 这不是一个有效的 json 吗?因为 jq 与上面的条目配合得很好:jq .host /tmp/test.json "host1-availabe_zone_A" "host2-availabe_zone_B" "host3-availabe_zone_A"
  • jq 可以遍历单独的 JSON 值的,这就是你所拥有的。

标签: json bash zsh jq


【解决方案1】:

您只是在计算 json 中的值。拆分出你要计算的部分

$ jq -nr 'inputs.host/"-"|last' input.json
availabe_zone_A
availabe_zone_B
availabe_zone_A

那么你可以分组和计数:

$ jq -nr '[inputs.host/"-"|last]|group_by(.)[]|"\(.[0]) -> \(length)"' input.json
availabe_zone_A -> 2
availabe_zone_B -> 1

https://jqplay.org/s/g_8HgqiQ1o

或者在你去的时候迭代值计数:

$ jq -nr '
reduce (inputs.host/"-"|last) as $k ({}; .[$k] += 1)|to_entries[]|"\(.key) -> \(.value)"
' input.json
availabe_zone_A -> 2
availabe_zone_B -> 1

https://jqplay.org/s/S2oeLfMRNR

【讨论】:

    【解决方案2】:

    使用.host 获取host 属性。

    $ hosts_list='  {
        "status": "closed",
        "host": "host1-availabe_zone_A"
      }
      {
        "status": "closed",
        "host": "host2-availabe_zone_B"
      }
      {
        "status": "closed",
        "host": "host3-availabe_zone_A"
      }'
    $ for host in $(jq -r '.host' <<<  "$hosts_list")
    do
     echo "$host"
    done
    host1-availabe_zone_A
    host2-availabe_zone_B
    host3-availabe_zone_A
    

    使用-r 选项使其输出原始字符串,而不是用双引号括起来的 JSON 字符串。

    不要忘记引用变量,除非您故意需要对值进行分词和通配符匹配。

    【讨论】:

    • 这并没有为所述问题提供解决方案(因为它现在存在)。此外,如果用户只想打印键名,则仍然不需要使用 shell 循环。 ——
    • @peak 他在我写完答案后编辑了这个问题,最初它只是打印出来。这大概只是他真正想要对这些名字做的事情的简化。
    • 是的,这就是我在括号里加上注释的原因。
    【解决方案3】:

    在 program.jq 中有以下内容:

    # bag of words
    def bow(stream): 
      reduce stream as $word ({}; .[($word|tostring)] += 1);
    
    bow(inputs | .host | sub("^.*-availabe";"availabe"))
    

    调用:

    jq -n -f program.jq input.json
    

    生产

    {
      "availabe_zone_A": 2,
      "availabe_zone_B": 1
    }
    

    如果你真的想要 STRING --> N 格式的输出, 添加 -r 到命令行选项,并添加以下内容 两行program.jq:

    | to_entries[]
    | "\(.key) --> \(.value)"
    

    评论

    1. 您可能需要修正拼写(“available”与“availabe”)
    2. 如本例所示,jq 可以处理由 JSON 实体组成的输入流——即 JSON 流。

    【讨论】:

      猜你喜欢
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-07
      • 2016-07-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多