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

在Bash脚本中用jq构建多层JSON:动态指定数组索引问题

问题:Bash中使用jq动态指定数组索引构建多层JSON

我在Bash脚本中读取文本文件内容到数组,遍历元素尝试构建多层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

执行后得到的JSON如下:

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

我需要向nodes列表中添加多个对象,因此设置了count变量尝试指定数组索引:

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

但这种方式无法添加列表项,我还尝试过以下方案也未解决问题:

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')

要求必须使用变量来指定列表的索引。


解决方案

核心问题分析

  1. 变量类型不匹配:用--arg传入jq的count是字符串类型,而jq数组索引需要数字,直接使用会导致索引无效。
  2. 数组初始化逻辑错误:原脚本每次遇到Station行都会重新将nodes初始化为空数组,覆盖之前已添加的节点。

修改后的关键代码

针对Station行的处理逻辑修改如下:

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

    # 确保nodes数组已存在,不存在则初始化
    JSON=$(echo "$JSON" | jq 'if .nodes then . else .nodes = [] end')
    # 将count字符串转为数字后作为索引,添加/更新节点
    JSON=$(echo "$JSON" | jq --arg mac "$mac" --arg interface "$interface" --arg count "$count" \
        '.nodes[$count | tonumber] = {"mac": $mac, "interface": $interface}')
    count=$((count+1))
fi

完整修改后的脚本

#!/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" --arg datetime "$datetime" '. += $ARGS.named')
    fi

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

        JSON=$(echo "$JSON" | jq 'if .nodes then . else .nodes = [] end')
        JSON=$(echo "$JSON" | jq --arg mac "$mac" --arg interface "$interface" --arg count "$count" \
            '.nodes[$count | tonumber] = {"mac": $mac, "interface": $interface}')
        count=$((count+1))
    fi
done

# 输出最终JSON
echo "$JSON"

说明

  • 使用$count | tonumber将字符串类型的count转为数字,满足jq数组索引的类型要求。
  • 先判断nodes是否存在,不存在才初始化,避免覆盖已有数据。
  • 合并了节点属性的赋值操作,减少jq调用次数,提升效率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 12:13:12