I have object in JSON that has the structure as shown below and I want to convert it into a "fake 3D" associative BASH array with the following structure:
SHIPS[$mmsi:mmsi]=367513050
SHIPS[$mmsi:lat]=42.380329
...etc
In other words, I want the mmsi
value combined with the key from each object to become the index to the associative array.
Right now, I am doing the following. The drawback is that it relies on the mmsi
field to be the first field of each JSON object — which is probably true but also not very reliable.
This provides 3 objects: VESSEL_INDEX
with all mmsi
s, KEY_INDEX
with all existing keys, and VESSELS
that can be accessed as VESSELS[$mmsi:$key]
EDIT: for clarity/completeness, my final goal is to:
- declare an associated array
curl
in a JSON file from a URL- update the associated array (with keys
VESSELS[$mmsi:$key]
) with the keys/values provided in the JSON object while leaving any unmentioned elements of the array unchanged.
declare -A VESSELS
declare -a VESSEL_INDEX
declare -a KEY_INDEX
while read -r keyvalue
do
key="${keyvalue%%=*}"
value="${keyvalue#*=}"
if [[ "$key" == "mmsi" ]]
then
mmsi="$value"
[[ -n "$mmsi" ]] && VESSEL_INDEX+=("$mmsi")
fi
[[ ! " ${KEY_INDEX[*]} " =~ " ${key} " ]] && KEY_INDEX+=("${key}")
[[ -n "$mmsi" ]] && VESSELS["$mmsi:$key"]="$value"
done <<< "$(curl -sL "$AIS_URL/ships_full.json" | jq -r ".ships[]|to_entries|map("(.key)=(.value|tostring)")|.[]")"
with this input curled in:
{
"count": 2
"ships": [
{
"mmsi": 367513050,
"lat": 42.380329,
"lon": -71.042946,
"distance": 0.317654,
"mmsi_type": 1,
"level": -28.161266,
"count": 6895,
"ppm": 4.918982,
"heading": null,
"cog": null,
"speed": 0,
"to_bow": 10,
"to_stern": 17,
"to_starboard": 3,
"to_port": 5,
"shiptype": 52,
"msg_type": 0,
"country": "US",
"status": 0,
"callsign": "WDG2188",
"shipname": "VINCENT D. TIBBETTS",
"destination": "BOSTON",
"last_signal": 0
},
{
"mmsi": 367447520,
"lat": 42.324032,
"lon": -70.994347,
"distance": 3.777312,
"mmsi_type": 1,
"level": -37.657475,
"count": 1103,
"ppm": -1.157407,
"heading": 156,
"cog": 155.5,
"speed": 28.4,
"to_bow": 24,
"to_stern": 20,
"to_starboard": 9,
"to_port": 4,
"shiptype": 40,
"msg_type": 0,
"country": "US",
"status": 0,
"callsign": "WDF4062",
"shipname": "SALACIA",
"destination": "XX XXX>?? ???",
"last_signal": 0
},
],
"error": false
}
2
Answers
Thanks to @pmf's answers and hints, I now have the following which appears to work. Posting it here so others can see it:
Make
jq
construct adeclare
statement using brackets around the key and escaping with@sh
:Now you should be able to use the associative array
$SHIPS
in Bash: