首页 > 解决方案 > 使用 jq 获取列表项的每个类别计数

问题描述

我目前正在学习如何在 Linux 中使用 jq 和 shell,因为我正在为 Check_MK(以前称为 Nagios)开发自定义检查,并且我的应用程序(qBittorrent 及其WebUI API)返回 JSON 字符串。

目前,我已经能够仅使用简单的jq length. 现在,我想计算当前正在下载、播种或暂停的种子的数量。我只对 感兴趣state,所以如果我有 6 个种子,我的 JSON 可能看起来像这样:

[
  {
    "state": "uploading"
  },
  {
    "state": "downloading"
  },
  {
    "state": "downloading"
  },
  {
    "state": "downloading"
  },
  {
    "state": "pauseDL"
  },
  {
    "state": "pauseUP"
  }
]

在这里,jq length返回 6。我需要做什么才能获取 3 正在下载、1 正在上传、2 暂停和 0 错误等详细信息?

这是我的实际脚本:

#!/bin/sh
curl -s http://localhost:8080/query/torrents -o /tmp/torrents.json
count=$(jq length /tmp/torrents.json)
echo "0 qbt_Nb_torrents - $count"

echoCheck_MK 需要 的语法(如此所述)。

我已经阅读了多个有关过滤器的示例,但是当我们通过顶级属性进行过滤时,它们似乎都在工作。在这里,我的顶层基本上只是 [0],...,[5],所以它不适用于我在手册中找到的示例。

附加信息

WebUI API 说有 12 种不同的可能状态。这就是我打算将它们分开的方式:

downloading: queuedDL, checkingDL, downloading 
uploading: queuedUP, checkingUP, uploading 
pause: pausedUP, pausedDL 
error: error 
stalled: stalledUP, stalledDL, metaDL

根据 CheckMK 语法,我基本上需要输出如下内容:

0 qbt_Nb_torrents - 总共 6 个,3 个下载,1 个播种,2 个暂停,0 个停止,0 个错误

开头的第一个 0 表示 CheckMK 的 OK 状态。如果有任何停止的种子,我希望该状态变为 1,如果有任何错误的种子,则状态变为 2。示例:

2 个 qbt_Nb_torrents - 总共 8 个,3 个下载,1 个播种,2 个暂停,1 个停止,1 个错误

标签: jsonshelljqcategorization

解决方案


对于其他有相关问题但未分享 OP 特定要求的人:请参阅编辑历史记录!group_by在此答案的先前迭代中还有其他一些相关建议,包括使用。


如果您需要所有值的条目,即使是没有出现的值,您可以考虑:

jq -r '
  def filterStates($stateMap):
    if $stateMap[.] then $stateMap[.] else . end;

  def errorLevel:
    if (.["error"] > 0) then 2 else
      if (.["stalled"] > 0) then 1 else
        0
      end
    end;

  {"queuedDL": "downloading", 
   "checkingDL": "downloading",
   "queuedUP": "uploading", 
   "checkingUP": "uploading",
   "pausedUP": "pause", 
   "pausedDL": "pause",
   "stalledUP": "stalled", 
   "stalledDL": "stalled", 
   "metaDL": "stalled"} as $stateMap |

  # initialize an output array since we want 0 outputs for everything
  {"pause": 0,  "stalled": 0, "error": 0, "downloading": 0, "uploading": 0} as $counts |

  # count number of items which filter to each value
  reduce (.[].state | filterStates($stateMap)) as $state ($counts; .[$state]+=1) |

  # actually format an output string
  "\(. | errorLevel) qbt_Nb_torrents - \(values | add) total, \(.["downloading"]) downloading, \(.["uploading"]) seeding, \(.["pause"]) on pause, \(.["stalled"]) stalled, \(.["error"]) error"
' /tmp/torrents.json

推荐阅读