JSON 및 jq는 bash 배열/루프를 입력합니다.

JSON 및 jq는 bash 배열/루프를 입력합니다.

JSON 결과가 있는데 이를 확인하고 JSON 문자열에 있는 하나 이상의 값이 임계값을 초과하면 경고를 보내고 싶습니다.

이 bash 명령은 다음과 같습니다.

for sat in `docker exec -i storagenode wget -qO - localhost:14002/api/sno | jq .satellites[].id -r`; do docker exec -i storagenode wget -qO - localhost:14002/api/sno/satellite/$sat | jq .id,.audits; done

다음이 제공됩니다(발췌):

"12tRQrMTWUWwzwGh18i7Fqs67kmdhH9t6aToeiwbo5mfS2rUmo"
{
  "auditScore": 1,
  "suspensionScore": 1,
  "onlineScore": 0.9974358974358974,
  "satelliteName": "us2.storj.io:7777"
}
"1wFTAgs9DP5RSnCqKV1eLf6N9wtk4EAtmN5DpSxcs8EjT69tGE"
{
  "auditScore": 1,
  "suspensionScore": 1,
  "onlineScore": 0.9989041005632043,
  "satelliteName": "saltlake.tardigrade.io:7777"
}

이제 결과를 확인하고 싶습니다. 예를 들어 onlineScore가 0.9 미만인 경우(또는 boatingScore 또는 auditScore가 1.0 미만인 경우) 위성 이름도 포함하는 텍스트 알림을 생성하려고 합니다. 예:auditScore below threshold: 0.98 for us2.storj.io

나는 다음과 같이 시작할 수 있다고 생각합니다.jq를 사용하여 JSON 배열을 bash 변수로 변환), 그러나 결과를 반복하는 방법과 필드 이름을 지정하고 유효성을 검사하는 방법을 모르겠습니다.

jq -r '.[] | to_entries | .[] | .key + "=" + (.value | @sh)'

업데이트 #1

docker exec -i storagenode wget -qO - localhost:14002/api/sno

공급:

{"nodeID":"1veqEG5xuBNkt...","wallet":"12345","walletFeatures":["zksync"],"satellites":[{"id":"12tRQrMTWUWwzwGh18i7Fqs67kmdhH9t6aToeiwbo5mfS2rUmo","url":"us2.storj.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":4592556672},{"id":"1wFTAgs9DP5RSnCqKV1eLf6N9wtk4EAtmN5DpSxcs8EjT69tGE","url":"saltlake.tardigrade.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":513269323264},{"id":"121RTSDpyNZVcEU84Ticf2L1ntiuUimbWgfATz21tuvgk3vzoA6","url":"ap1.storj.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":70956116864},{"id":"12EayRS2V1kEsWESU9QMRseFhdxYxKicsiFmxrsLZHeLUtdps3S","url":"us1.storj.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":322340591104},{"id":"12L9ZFwhzVpuEKMUNUqkaTLGzwY9G24tbiigLiXpmZWKwmcNDDs","url":"eu1.storj.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":148740125312},{"id":"12rfG3sh9NCWiX3ivPjq2HtdLmbqCrvHVEzJubnzFzosMuawymB","url":"europe-north-1.tardigrade.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":100681406976}],"diskSpace":{"used":1162257094528,"available":9500000000000,"trash":43196690332,"overused":0},"bandwidth":{"used":31670206976,"available":0},"lastPinged":"2022-01-02T07:55:51.886776586Z","version":"1.45.3","allowedVersion":"1.24.0","upToDate":true,"startedAt":"2021-12-31T00:00:32.209840775Z"}

이:

docker exec -i storagenode wget -qO - localhost:14002/api/sno/satellite/1wFTAgs9DP5RSnCqKV1eLf6N9wtk4EAtmN5DpSxcs8EjT69tGE

공급:

{"id":"1wFTAgs9DP5RSnCqKV1eLf6N9wtk4EAtmN5DpSxcs8EjT69tGE","storageDaily":[{"atRestTotal":11726579066524.266,"intervalStart":"2022-01-01T00:00:00Z"}],"bandwidthDaily":[{"egress":{"repair":390576640,"audit":7424,"usage":2373615872},"ingress":{"repair":2745100032,"usage":26744320},"delete":0,"intervalStart":"2022-01-01T00:00:00Z"},{"egress":{"repair":143168256,"audit":3584,"usage":786989568},"ingress":{"repair":1034401280,"usage":8107264},"delete":0,"intervalStart":"2022-01-02T00:00:00Z"}],"storageSummary":11726579066524.266,"bandwidthSummary":7508714240,"egressSummary":3694361344,"ingressSummary":3814352896,"currentStorageUsed":513269323264,"audits":{"auditScore":1,"suspensionScore":1,"onlineScore":0.9989041005632043,"satelliteName":"saltlake.tardigrade.io:7777"},"auditHistory":{"score":0.9989041005632043,"windows":[{"windowStart":"2021-12-03T00:00:00Z","totalCount":36,"onlineCount":36},{"windowStart":"2021-12-03T12:00:00Z","totalCount":30,"onlineCount":30},{"windowStart":"2021-12-04T00:00:00Z","totalCount":43,"onlineCount":42},{"windowStart":"2021-12-04T12:00:00Z","totalCount":68,"onlineCount":68},{"windowStart":"2021-12-05T00:00:00Z","totalCount":53,"onlineCount":53},{"windowStart":"2021-12-05T12:00:00Z","totalCount":36,"onlineCount":36},{"windowStart":"2021-12-06T00:00:00Z","totalCount":33,"onlineCount":33},{"windowStart":"2021-12-06T12:00:00Z","totalCount":53,"onlineCount":53},{"windowStart":"2021-12-07T00:00:00Z","totalCount":27,"onlineCount":27},{"windowStart":"2021-12-07T12:00:00Z","totalCount":65,"onlineCount":65},{"windowStart":"2021-12-08T00:00:00Z","totalCount":30,"onlineCount":30},{"windowStart":"2021-12-08T12:00:00Z","totalCount":27,"onlineCount":27},{"windowStart":"2021-12-09T00:00:00Z","totalCount":46,"onlineCount":46},{"windowStart":"2021-12-09T12:00:00Z","totalCount":48,"onlineCount":48},{"windowStart":"2021-12-10T00:00:00Z","totalCount":49,"onlineCount":49},{"windowStart":"2021-12-10T12:00:00Z","totalCount":67,"onlineCount":67},{"windowStart":"2021-12-11T00:00:00Z","totalCount":71,"onlineCount":71},{"windowStart":"2021-12-11T12:00:00Z","totalCount":52,"onlineCount":52},{"windowStart":"2021-12-12T00:00:00Z","totalCount":59,"onlineCount":59},{"windowStart":"2021-12-12T12:00:00Z","totalCount":77,"onlineCount":77},{"windowStart":"2021-12-13T00:00:00Z","totalCount":79,"onlineCount":79},{"windowStart":"2021-12-13T12:00:00Z","totalCount":79,"onlineCount":79},{"windowStart":"2021-12-14T00:00:00Z","totalCount":65,"onlineCount":65},{"windowStart":"2021-12-14T12:00:00Z","totalCount":59,"onlineCount":59},{"windowStart":"2021-12-15T00:00:00Z","totalCount":87,"onlineCount":87},{"windowStart":"2021-12-15T12:00:00Z","totalCount":82,"onlineCount":81},{"windowStart":"2021-12-16T00:00:00Z","totalCount":96,"onlineCount":96},{"windowStart":"2021-12-16T12:00:00Z","totalCount":66,"onlineCount":64},{"windowStart":"2021-12-17T00:00:00Z","totalCount":36,"onlineCount":36},{"windowStart":"2021-12-17T12:00:00Z","totalCount":48,"onlineCount":48},{"windowStart":"2021-12-18T00:00:00Z","totalCount":37,"onlineCount":37},{"windowStart":"2021-12-18T12:00:00Z","totalCount":60,"onlineCount":60},{"windowStart":"2021-12-19T00:00:00Z","totalCount":69,"onlineCount":69},{"windowStart":"2021-12-19T12:00:00Z","totalCount":32,"onlineCount":32},{"windowStart":"2021-12-20T00:00:00Z","totalCount":53,"onlineCount":53},{"windowStart":"2021-12-20T12:00:00Z","totalCount":37,"onlineCount":37},{"windowStart":"2021-12-21T00:00:00Z","totalCount":80,"onlineCount":80},{"windowStart":"2021-12-21T12:00:00Z","totalCount":57,"onlineCount":57},{"windowStart":"2021-12-22T00:00:00Z","totalCount":46,"onlineCount":46},{"windowStart":"2021-12-22T12:00:00Z","totalCount":33,"onlineCount":33},{"windowStart":"2021-12-23T00:00:00Z","totalCount":42,"onlineCount":42},{"windowStart":"2021-12-23T12:00:00Z","totalCount":73,"onlineCount":73},{"windowStart":"2021-12-24T00:00:00Z","totalCount":35,"onlineCount":35},{"windowStart":"2021-12-24T12:00:00Z","totalCount":44,"onlineCount":44},{"windowStart":"2021-12-25T00:00:00Z","totalCount":81,"onlineCount":81},{"windowStart":"2021-12-25T12:00:00Z","totalCount":43,"onlineCount":43},{"windowStart":"2021-12-26T00:00:00Z","totalCount":62,"onlineCount":62},{"windowStart":"2021-12-26T12:00:00Z","totalCount":79,"onlineCount":79},{"windowStart":"2021-12-27T00:00:00Z","totalCount":70,"onlineCount":70},{"windowStart":"2021-12-27T12:00:00Z","totalCount":90,"onlineCount":90},{"windowStart":"2021-12-28T00:00:00Z","totalCount":65,"onlineCount":65},{"windowStart":"2021-12-28T12:00:00Z","totalCount":77,"onlineCount":77},{"windowStart":"2021-12-29T00:00:00Z","totalCount":83,"onlineCount":83},{"windowStart":"2021-12-29T12:00:00Z","totalCount":99,"onlineCount":99},{"windowStart":"2021-12-30T00:00:00Z","totalCount":74,"onlineCount":74},{"windowStart":"2021-12-30T12:00:00Z","totalCount":84,"onlineCount":84},{"windowStart":"2021-12-31T00:00:00Z","totalCount":70,"onlineCount":70},{"windowStart":"2021-12-31T12:00:00Z","totalCount":93,"onlineCount":93},{"windowStart":"2022-01-01T00:00:00Z","totalCount":120,"onlineCount":120},{"windowStart":"2022-01-01T12:00:00Z","totalCount":112,"onlineCount":112},{"windowStart":"2022-01-02T00:00:00Z","totalCount":46,"onlineCount":46}]},"priceModel":{"EgressBandwidth":2000,"RepairBandwidth":1000,"AuditBandwidth":1000,"DiskSpace":150},"nodeJoinedAt":"2021-05-11T20:11:14.910165Z"}

죄송합니다. 여기서 거대한 json 콘텐츠를 더 나은 방식으로 형식화하는 방법을 모르겠습니다.

업데이트 #2

http://localhost:14002/api/sno/satellites이전에는 몰랐던 결과가 있습니다 . 결과 :

{
...
   "storageSummary": 6.8624392E13,
...
   "audits": [
      {
         "auditScore": 1,
         "suspensionScore": 1,
         "onlineScore": 0.99743587,
         "satelliteName": "us2.storj.io:7777"
      },
      {
         "auditScore": 1,
         "suspensionScore": 1,
         "onlineScore": 0.9992917,
         "satelliteName": "saltlake.tardigrade.io:7777"
      },
...
      {
         "auditScore": 1,
         "suspensionScore": 1,
         "onlineScore": 0.99930555,
         "satelliteName": "ap1.storj.io:7777"
      }
   ]
}

답변1

일반적으로 명령 대체 결과를 반복하지 않는 것이 좋습니다. 루프 실행이 시작되기 전에 대체 명령의 실행이 완료되어야 하기 때문에 이는 우아하지 않으며, 대체 명령의 전체 결과가 메모리에 저장되어야 하기 때문에 비효율적이며, 쉘이 다음 작업을 수행할 수 있어야 하기 때문에 오류가 발생하기 쉽습니다. 명령을 분할하면 의 출력에 공백이 포함되어 결과 단어가 파일 이름 글로빙에 적용됩니다.

루프 read에서 가장 잘 사용됩니다:while

#!/bin/sh

curl -s 'localhost:14002/api/sno' |
jq -r '.satellites[].id' |
while IFS= read -r id; do
        curl -s 'localhost:14002/api/sno/satellite/'"$id"
done |
jq -r \
        --argjson auditScore 1 \
        --argjson suspensionScore 1 \
        --argjson onlineScore 0.9 \
        '.audits as $a | $a.satelliteName as $name |
        reduce ($ARGS.named|keys[]) as $key (
                [];
                if $a[$key] < $ARGS.named[$key] then (
                        . + ["\($key) below threshold: \($a[$key]) for \($name)"]
                ) else . end
        ) | .[]'

이 스크립트는 사용자가 REST 엔드포인트에 연결할 수 있다고 가정합니다 localhost:14002(예: Docker 컨테이너가 이 포트를 노출할 수 있음). docker exec명령을 사용하여 API에 액세스 해야 하는 경우 일반 호출을 로 바꾸세요 curl.

docker exec -i curl -s 'localhost:14002/api/sno'

업데이트된 질문의 경우 api/sno/satellites엔드포인트를 사용하세요.

#!/bin/sh

curl -s 'localhost:14002/api/sno/satellites' |
jq -r \
        --argjson auditScore 1 \
        --argjson suspensionScore 1 \
        --argjson onlineScore 0.9 \
        '.audits[] as $a | $a.satelliteName as $name |
        reduce ($ARGS.named|keys[]) as $key (
                [];
                if $a[$key] < $ARGS.named[$key] then (
                        . + ["\($key) below threshold: \($a[$key]) for \($name)"]
                ) else . end
        ) | .[]'

이는 표현식에 대한 약간의 조정을 제외하면 본질적으로 위와 동일한 코드이지만 모든 ID와 루프를 가져오기 위해 jq첫 번째 호출을 우회합니다 .curl

답변2

가능한 답을 찾았습니다스택 오버플로:


for sat in `docker exec -i storagenode wget -qO - localhost:14002/api/sno | jq .satellites[].id -r`
do
  docker exec -i storagenode wget -qO - localhost:14002/api/sno/satellite/$sat \
  | jq --raw-output \
    --argjson auditThreshold 1 \
    --argjson suspensionThreshold 1 \
    --argjson onlineThreshold 1 \
    '.audits
      | .satelliteName as $name
      | (
          [{auditScore}, $auditThreshold],
          [{suspensionScore}, $suspensionThreshold],
          [{onlineScore}, $onlineThreshold]
        )
      | select(.[0][] < .[1])
      | "\(.[0] | keys[]) (\(.[0][])) below threshold (\(.[1])) for \($name)"
    '
done

관련 정보