0

The following code works, but what is the industry-standard way of doing this? I'm more comfortable with languages that return FALSE when they fail. The idea of comparing a string with "null" doesn't sit right with me. Is jq actually returning the string "null" or is bash translating the false/empty return to that string?

Note, the array is nested in the JSON file and has an unknown number of elements.

#!/bin/bash

NEW_PEERS_JSON="${CNODE_HOME}/files/peers/20201309.json"

index=0
while [ 1 ]
do
        addr=$(jq -r .Producers[$index].addr < $NEW_PEERS_JSON)
        if [ "$addr" == "null" ]

        then
                break
        fi
        echo $addr
        index=$index+1
done

the JSON file looks like this:

{ "resultcode": "201", "networkMagic": "764824073", "ipType":4, "Producers": [
  { "addr": "xx.xxx.xxx.xx", "port": 3030, "valency": 1, "distance":14 },
  { "addr": "xx.xxx.xxx.xx", "port": 3001, "valency": 1, "distance":955 },
  { "addr": "xx.xxx.xxx.xx", "port": 3001, "valency": 1, "distance":1307 },
  { "addr": "xx.xxx.xxx.xx", "port": 3001, "valency": 1, "distance":1976 },
  { "addr": "xx.xxx.xxx.xx", "port": 4251, "valency": 1, "distance":3025 },
  { "addr": "xx.xxx.xxx.xx", "port": 3001, "valency": 1, "distance":3497 },
  { "addr": "xx.xxx.xxx.xx", "port": 3001, "valency": 1, "distance":3539 },
  { "addr": "xx.xxx.xxx.xx", "port": 3301, "valency": 1, "distance":3685 },
  { "addr": "xx.xxx.xxx.xx", "port": 4002, "valency": 1, "distance":7303 },
  { "addr": "xx.xxx.xxx.xx", "port": 4601, "valency": 1, "distance":7737 },
  { "addr": "xx.xxx.xxx.xx", "port": 4001, "valency": 1, "distance":7866 }
] }

Thanks!

Adam Winter
  • 1,680
  • 1
  • 12
  • 26

1 Answers1

0

Run jq only once with a filter that emits your addresses one-per-line, using a while read loop to iterate over lines of output that one copy of jq emits. Per BashFAQ #1:

#!/bin/bash

NEW_PEERS_JSON="${CNODE_HOME}/files/peers/20201309.json"

while IFS= read -r addr; do
  echo "Handling address: $addr"
done < <(jq -r '.Producers[].addr' <"$NEW_PEERS_JSON")

This is much, much more efficient than running a separate copy of jq per item you want to extract.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Yes! That was the other concern I had with what I was doing. Thank you! – Adam Winter Sep 14 '20 at 00:21
  • What if the json file were compacted, though, and there was no line break between the elements? – Adam Winter Sep 14 '20 at 00:42
  • @AdamWinter, `jq` itself adds line breaks between query results. If you aren't using `-r` you can use `-c` to tell it to emit one JSON document per line (writing JSONL format); one can also use `-j` and construct jq queries that NUL-separate individual results. – Charles Duffy Sep 14 '20 at 16:03