You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将3D JSON对象转换为Bash中的"伪3D"关联数组

如何将JSON船舶数据转换为Bash的"伪3D"关联数组

需求说明

我需要把给定结构的JSON数据转换成Bash中的"伪3D"关联数组,格式示例如下:

VESSELS[$mmsi:mmsi]=367513050
VESSELS[$mmsi:lat]=42.380329
...

核心要求是用mmsi值+对象键作为关联数组的索引。

最终目标:

  • 声明一个关联数组
  • 通过curl从URL获取JSON文件
  • 用JSON中的键值对更新关联数组(键格式为VESSELS[$mmsi:$key]),同时保留数组中未被提及的原有元素不变

现有实现的问题

我目前的实现依赖一个不可靠的假设:mmsi字段是每个JSON对象的首个字段。现有代码会生成三个变量:存储所有mmsi的VESSEL_INDEX数组、存储所有键的KEY_INDEX数组,以及可通过VESSELS[$mmsi:$key]访问的VESSELS关联数组。

现有代码:

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)\")|.[]")"

输入的JSON示例

{
  "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
}

改进方案

要解决依赖mmsi字段顺序的问题,我们可以让jq先提取每个船舶对象的mmsi,再把mmsi和每个键值对组合输出,这样不管mmsi在JSON中的位置如何,都能正确获取到。

改进后的代码:

declare -A VESSELS
declare -a VESSEL_INDEX
declare -a KEY_INDEX

# 用jq先获取mmsi,再遍历所有键值对输出"mmsi:key=value"格式的行
while IFS='=' read -r index value
do
    # 拆分index为mmsi和key
    mmsi="${index%%:*}"
    key="${index#*:}"
    
    # 更新VESSEL_INDEX(去重)
    if [[ ! " ${VESSEL_INDEX[*]} " =~ " ${mmsi} " ]]; then
        VESSEL_INDEX+=("$mmsi")
    fi
    
    # 更新KEY_INDEX(去重)
    if [[ ! " ${KEY_INDEX[*]} " =~ " ${key} " ]]; then
        KEY_INDEX+=("$key")
    fi
    
    # 更新关联数组
    VESSELS["$index"]="$value"

done <<< "$(curl -sL "$AIS_URL/ships_full.json" | jq -r '.ships[] | .mmsi as $mmsi | to_entries[] | "\($mmsi):\(.key)=\(.value|tostring)"')"

方案优势

  1. 不再依赖mmsi在JSON对象中的位置,不管mmsi是第几个字段都能正确处理
  2. jq直接输出mmsi:key=value格式的行,避免了在bash循环中临时存储mmsi的逻辑,减少出错概率
  3. 保留了原有需求中的VESSEL_INDEX和KEY_INDEX数组,同时正确更新VESSELS关联数组
  4. 自动保留数组中未被JSON提及的原有元素(因为只更新JSON中存在的键值对,不会清空整个数组)

内容的提问来源于stack exchange,提问作者kx1t

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 13:35:21