代码之家  ›  专栏  ›  技术社区  ›  dan

使用jq获取列表项的每个类别计数

  •  1
  • dan  · 技术社区  · 7 年前

    我目前正在学习如何在Linux中使用jq和shell,因为我正在为Check_MK(以前称为Nagios)和我的应用程序(qBittorrent)开发自定义检查,并使用它们的 WebUI API

    jq length . 现在,我想计算一下当前正在下载、播种或暂停的种子流的数量。我只对 state

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

    在这里, jq长度

    这是我的剧本:

    #!/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"
    

    的语法 echo 是Check MK所要求的(如所述 here ).

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

    附加信息

    webuiapi说有12种不同的可能状态。我打算这样把他们分开:

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

    0 qbt\u Nb\u torrents-共6个,3个下载,1个种子,2个暂停,0个暂停,0个错误

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

    2个qbt\u Nb\u torrents-共8个,3个下载,1个种子,2个暂停,1个暂停,1个错误

    3 回复  |  直到 7 年前
        1
  •  4
  •   Charles Duffy    7 年前

    对于其他有相关问题,但没有分享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
    
        2
  •  1
  •   peak    7 年前

    # bag of words
    def bow(init; s): reduce s as $word (init; .[$word] += 1) ;
    

    还要注意初始化函数:

    # initialize an output object since we minimally want 0s
    def init:
      {} | {pause,stalled,error,downloading,uploading} | map_values(0);
    

    有了这些额外的抽象,“main”程序就变成了两行代码。

      def filterStates($stateMap):
        if $stateMap[.] then $stateMap[.] else . end ;
    
      def errorLevel:
        if .error > 0 then 2
        elif .stalled > 0 then 1
        else 0
        end ;
    
      def stateMap:
        {"queuedDL": "downloading", 
         "checkingDL": "downloading",
         "queuedUP": "uploading", 
         "checkingUP": "uploading",
         "pausedUP": "pause", 
         "pausedDL": "pause",
         "stalledUP": "stalled", 
         "stalledDL": "stalled", 
         "metaDL": "stalled"} ;
    

      # count number of items which map to each value
      bow(init; .[].state | filterStates(stateMap))
      # format an output string
      | "\(errorLevel) qbt_Nb_torrents - \(values | add) total, \(.downloading) downloading, \(.uploading) seeding, \(.pause) on pause, \(.stalled) stalled, \(.error) error"
    
        3
  •  0
  •   dan    7 年前

    万一有人想知道我到底用了什么来回答查尔斯·达菲的精彩答案,下面是全文 /usr/lib/check_mk_agent/local/qbittorrent shell脚本,允许checkmk(1.5.0 raw)获取我认为与在服务器上的专用VM中运行的qBittorrent应用程序(qBittorrent v3.3.7 Web UI)最相关的信息:

    #!/bin/sh
    curl -s http://localhost:8080/query/transferInfo -o /tmp/transferInfo.json
    curl -s http://localhost:8080/query/torrents -o /tmp/torrents.json
    
    if [ -e /tmp/transferInfo.json ]
    then
     dwl=$(jq .dl_info_speed /tmp/transferInfo.json)
     dwl_MB=$(bc <<< "scale=2;$dwl/1048576")
     upl=$(jq .up_info_speed /tmp/transferInfo.json)
     upl_MB=$(bc <<< "scale=2;$upl/1048576")
     echo "0 qbt_Global_speed download=$dwl_MB|upload=$upl_MB Download: $dwl_MB MB/s, Upload: $upl_MB MB/s"
     rm -f /tmp/transferInfo.json
    else
     echo "3 qbt_Global_speed download=0|upload=0 Can't get the information from qBittorrent WebUI API"
    fi
    
    if [ -e /tmp/torrents.json ]
    then    
     jq -r '
       def filterStates($stateMap):
        if $stateMap[.] then $stateMap[.] else . 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) |
    
       # output string
       "P qbt_Nb_torrents total=\(values|add)|downloading=\(.["downloading"])|seeding=\(.["uploading"])|pause=\(.["pause"])|stalled=\(.["stalled"]);0|error=\(.["error"]);0;0 total is \(values|add), downloading is \(.["downloading"]), seeding is \(.["uploading"]), pause is \(.["pause"])"
    ' /tmp/torrents.json
    
     rm -f /tmp/torrents.json
    else
     echo "3 qbt_Nb_torrents total=0|downloading=0|seeding=0|pause=0|stalled=0;0|error=0;0;0 Can't get the information from qBittorrent WebUI API"
    fi
    

    以下是1个失速torrent的输出:

    0 qbt_Global_speed download=0|upload=0 Download: 0 MB/s, Upload: 0 MB/s
    P qbt_Nb_torrents total=1|downloading=0|seeding=0|pause=0|stalled=1;0|error=0;0;0 total is 1, downloading is 0, seeding is 0, pause is 0
    

    这个 errorLevel 我认为我需要的东西(见查尔斯的答案)不是必需的,因为Check-MK是如何工作的;它自己处理阈值 the metric parameter 指定警告和临界值时。

    以下是支票中的内容:

    Check_MK view

    注意Check\u MK是如何自动添加暂停和出错的torrents的。这是因为指定了警告和/或临界阈值。一般而言,指标(有或没有阈值)对于提供详细的相关图表非常重要。