jqlang / jq

Command-line JSON processor
https://jqlang.github.io/jq/
Other
30.06k stars 1.55k forks source link

Сreating multilevel json with the jq utility in a bash script #3154

Open AndryAsh opened 1 month ago

AndryAsh commented 1 month ago

I get the contents of a text file into an array and then sequentially get the elements of the array and try to add the elements to the json:

#!/bin/bash

JSON=$(jq -n '')
readarray -t array < ./station.sample
count=0

for e in "${array[@]}"
do
    if echo "$e" | grep -Eq '^[0-9]{10}' >/dev/null
      then
        timestamp=$e
        datetime=`date +'%Y-%m-%d %H:%M:%S' -d "@$e"`
        JSON=$(echo $JSON | jq --arg timestamp "${timestamp}" '. += $ARGS.named')
        JSON=$(echo $JSON | jq --arg datetime "${datetime}" '. += $ARGS.named')
    fi

    if echo "$e" | grep '^Station ' >/dev/null
      then
        NODE=$(jq -n '')
        mac=`echo "$e" | awk '{ print $2 }'`
        interface=`echo "$e" | awk '{ print $4 }' | rev | cut -c2- | rev`

        JSON=$(echo $JSON | jq --argjson nodes "[]" '. += $ARGS.named')
        JSON=$(echo $JSON | jq --arg mac "${mac}" --arg count "${count}" '.nodes[0] += {"mac": $mac}')
    JSON=$(echo $JSON | jq --arg interface "${interface}" '.nodes[0] += {"interface": $interface}')

        count=$((count+1))
    fi
done

As a result, I get a json like this:

{
  "timestamp": "1721396365",
  "datetime": "2024-07-19 16:39:25",
  "nodes": [
    {
      "mac": "14:88:00:00:00:06"
    }
  ]
}

But I need to add multiple objects to the list, so I set a count variable and want to use it to specify the index of the list:

JSON=$(echo $JSON | jq --arg mac "${mac}" --arg count "${count}" '.nodes[$count] += {"mac": $mac}')

But in this variant adding list items doesn't work.

How can I dynamically specify the index of the list?

I've tried all the options that came to mind, but I haven't found a solution yet:

 NODE=$(echo $NODE | jq --arg mac "$mac" '. += $ARGS.named')
 NODE=$(echo $NODE | jq --arg interface "${interface}" '. += $ARGS.named')
 JSON=$(echo $JSON | jq --argjson node "${NODE}" '.nodes[.nodes | length] = $ARGS.named')

It is necessary to use a variable to specify the index of the list.

itchyny commented 1 month ago

Could you share a sample input file with at least five lines and its expected JSON result? Your use case looks achievable with one jq command but the expectated result is ambiguous.

itchyny commented 1 month ago

Something like .nodes += [{$mac}] should work.