skip to Main Content

Have bash variable contain every execution one level only but not know JSON structure, example:

$ echo $JJJ

{ "media": "heat", "meter": "kamheat", "name": "Heato", "id": "32323232", "flow_return_temperature_difference_c": 37.06, "forward_energy_m3c": 67136, "max_flow_m3h": 22.75, "max_power_kw": 869, "on_time_h": 17232, "on_time_at_error_h": 28, "power_kw": 560, "return_energy_m3c": 37929, "t1_temperature_c": 81.37, "t2_temperature_c": 44.31, "target_energy_kwh": 3200000, "target_volume_m3": 81847, "total_energy_consumption_kwh": 3363200, "total_volume_m3": 85656, "volume_flow_m3h": 13.16, "fabrication_no": "84853230", "meter_datetime": "2024-01-15 11:46", "status": "OK", "target_date": "2024-01-01", "timestamp": "2025-01-16T14:05:13Z" }

Next time can have other one level JSON with unknown pairs like eg:

{ "media": "water", "meter": "aptnaa1", "name": "Meter", "id": "56434345", "max_flow_m3h": 1.7,"on_time_h": 17232, "on_time_at_error_h": 28, "target_volume_m3": 1200, "total_volume_m3": 965.78, "volume_flow_m3h": 3.16, "fabrication_no": "89853230", "meter_datetime": "2024-01-12 11:46", "status": "OK", "target_date": "2024-01-01", "timestamp": "2025-01-16T14:05:13Z" }

I’d like to convert the JSON into bash array

declare -A array_telegram=()

and for each JSON pair put the pairs into array like this:

array_telegram+=(["media"]="heat")
array_telegram+=(["meter"]="kamheat")
.....
array_telegram+=(["timestamp"]="2025-01-16T14:05:13Z")

How to put not-know JSON structure into bash array?

Try use jq but without success.

3

Answers


  1. Use a JSON processor like jq, and have it e.g. produce the declare statement:

    unset array_telegram; declare -A array_telegram="($(jq -r '
      to_entries[] | @sh "[(.key)]=(.value)"
    ' <<< "$JJJ"))"
    

    With newer versions of Bash you can also use the key value form for declaration:

    unset array_telegram; declare -A array_telegram="($(jq -r '
      to_entries[] | .key, .value | @sh
    ' <<< "$JJJ"))"
    

    Both produce the populated and ready-to-use associative bash array:

    $ echo "${array_telegram[timestamp]}"
    2025-01-16T14:05:13Z
    
    $ declare -p array_telegram
    declare -A array_telegram=([max_flow_m3h]="22.75" [target_energy_kwh]="3200000" [on_time_h]="17232" [id]="32323232" [target_date]="2024-01-01" [forward_energy_m3c]="67136" [volume_flow_m3h]="13.16" [total_energy_consumption_kwh]="3363200" [power_kw]="560" [t1_temperature_c]="81.37" [total_volume_m3]="85656" [flow_return_temperature_difference_c]="37.06" [meter_datetime]="2024-01-15 11:46" [media]="heat" [max_power_kw]="869" [t2_temperature_c]="44.31" [target_volume_m3]="81847" [fabrication_no]="84853230" [timestamp]="2025-01-16T14:05:13Z" [on_time_at_error_h]="28" [meter]="kamheat" [return_energy_m3c]="37929" [status]="OK" [name]="Heato" )
    
    Login or Signup to reply.
  2. A more verbose form of @pmf’s answer: a while loop to read the values from the jq output

    declare -A array_telegram
    while IFS=$'t' read -r key value; do
        array_telegram["$key"]=$value
    done < <(
        jq -r 'to_entries[] | [.key, .value] | @tsv' <<< "$JJJ"
    )
    
    Login or Signup to reply.
  3. To parse unknown JSON structure into a Bash associative array (declare -A) dynamically, you can use jq to extract the key-value pairs and populate the array. Here’s how you can achieve it:

    #!/bin/bash
    
    # JSON input
    JJJ='{ "media": "heat", "meter": "kamheat", "name": "Heato", "id": 
    "32323232", "flow_return_temperature_difference_c": 37.06, 
    "forward_energy_m3c": 67136, "max_flow_m3h": 22.75, "max_power_kw": 869, 
    "on_time_h": 17232, "on_time_at_error_h": 28, "power_kw": 560, 
    "return_energy_m3c": 37929, "t1_temperature_c": 81.37, "t2_temperature_c": 
    44.31, "target_energy_kwh": 3200000, "target_volume_m3": 81847, 
    "total_energy_consumption_kwh": 3363200, "total_volume_m3": 85656, 
    "volume_flow_m3h": 13.16, "fabrication_no": "84853230", "meter_datetime": 
    "2024-01-15 11:46", "status": "OK", "target_date": "2024-01-01", "timestamp": 
    "2025-01-16T14:05:13Z" }'
    
    # Declare an associative array
    declare -A array_telegram
    
    # Use jq to parse the JSON and fill the associative array
       while IFS="=" read -r key value; do
    # Remove surrounding quotes from the value
      value=$(echo "$value" | sed 's/^"(.*)"$/1/')
    # Add the key-value pair to the array
      array_telegram["$key"]="$value"
    done < <(echo "$JJJ" | jq -r 'to_entries | .[] | "(.key)=(.value)"')
    
     # Print the array to verify
     for key in "${!array_telegram[@]}"; do
       echo "array_telegram["$key"]="${array_telegram[$key]}""
     done
    

    So to explain to you :

    1.  JSON Parsing with jq:
    

    The jq -r ‘to_entries | .[] | "(.key)=(.value)"’ command converts JSON into key-value pairs in the format key=value.

    2.  Iterating Through Key-Value Pairs:
    

    A while loop reads each key-value pair, using IFS="=" to split the line.

    3.  Removing Quotes from String Values:
    

    sed removes surrounding quotes from values if they exist.

    4.  Populating the Associative Array:
    

    each key-value pair is added to the array_telegram array.

    Output

    For the given JSON, the output will look like this:

    array_telegram["media"]="heat"
    array_telegram["meter"]="kamheat"
    array_telegram["name"]="Heato" 
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search