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

使用变量向Bash字典添加键值对时遇command not found错误

Bash脚本动态创建关联数组报错解决:array[key]=value: command not found

我尝试通过一系列for循环从JSON文件拉取数据,动态创建键值对集合——先生成数组,再迭代定义键值对。但运行脚本时持续报错:array[key]=value: command not found,待写入数组的信息看似正确,却一直出现这个错误。我用$array[$key]=$value的方式向数组添加元素,不确定这种操作是否可行,试了多种脚本变体都报同样的错。

以下是当前完整脚本:

#!/bin/bash 

backupTargets=()
#currently active nodes
nodeArray=()
#add proxmox api token
pveTOK=FOO

get_nodes () { 
#grab currently active nodes 
curl -s -k -H \"Authorization: PVEAPIToken=$pveTOK\" https:///api2/json/nodes | jq . > nodes
#use jq to extract inital data from the curl command, remove returns with tr and use sed to clean things up to make it ready to be placed 
#in an array
nodes=$(jq [.data[].node] nodes | tr -d '\\n'| sed 's/\\[//g; s/\\]//g; s/ //g; s/,/ /g; s/\\"//g')
nodeArray=($nodes)
}

declare_variables () {
for node in \"${nodeArray[@]}\"
do
declare -A $node
done
}

get_backupVMs () {
#some nested for loops that iterate over the nodes to create a dictionary that contains each vm and the associated tags
for node in \"${nodeArray[@]}\"
do
hosts=()
curl -s -k -H \"Authorization: PVEAPIToken=$pveTOK\" https:///api2/json/nodes/$node/qemu | jq . > $node
name=$(jq [.data[].name] $node | tr -d '\\n'| sed 's/\\[//g; s/\\]//g; s/ //g; s/,/ /g; s/\\"//g')
hosts+=($name)
for host in \"${hosts[@]}\"
do
tags=$(jq '.data[] | select(.name=='\\\\"$host\\\\"').tags' $node | sed 's/\\[//g; s/\\]//g; s/ //g; s/;/ /g; s/\\"//g')
$node[$host]=$tags
done
done
}

get_nodes
declare_variables
get_backupVMs

错误原因分析

  1. 动态关联数组赋值语法错误:
    $node[$host]=$tags 是错误写法,Bash会把这个表达式解析为执行一个名为$node[$host]的命令,而非数组赋值操作。要操作动态命名的关联数组,需要用**命名引用(nameref)**来间接引用数组。
  2. 冗余的字符串转义:
    脚本中多处出现\"${nodeArray[@]}\"这种写法,转义引号会导致变量被包裹在引号中,后续curl请求和jq解析会出现无效参数问题。
  3. jq表达式不规范:
    jq的查询表达式需要用单引号包裹,比如jq '[.data[].node]' nodes,否则Shell会解析方括号等特殊字符,导致jq执行出错。
  4. 数据提取逻辑冗余:
    用tr+sed处理jq输出容易出错,直接让jq输出空格分隔的字符串更可靠。

修正后的脚本

#!/bin/bash 

backupTargets=()
# 当前活跃节点
nodeArray=()
# 填入你的Proxmox API Token
pveTOK=FOO
# Proxmox API地址,补充完整域名/IP
PVE_API_URL="https://your-proxmox-host/api2/json"

get_nodes () { 
    # 获取当前活跃节点
    curl -s -k -H "Authorization: PVEAPIToken=$pveTOK" "$PVE_API_URL/nodes" | jq . > nodes.json
    # 用jq直接输出空格分隔的节点名,无需额外处理
    nodeArray=($(jq -r '.data[].node' nodes.json))
    rm -f nodes.json
}

declare_variables () {
    # 为每个节点创建关联数组,并通过nameref后续操作
    for node in "${nodeArray[@]}"
    do
        declare -A "$node"
    done
}

get_backupVMs () {
    # 遍历节点,收集每个VM的标签到对应关联数组
    for node in "${nodeArray[@]}"
    do
        # 获取当前节点的QVM列表
        curl -s -k -H "Authorization: PVEAPIToken=$pveTOK" "$PVE_API_URL/nodes/$node/qemu" | jq . > "${node}_qemu.json"
        
        # 用jq一次性提取VM名和对应标签,避免嵌套循环
        jq -r '.data[] | "\(.name) \(.tags)"' "${node}_qemu.json" | while read -r host tags; do
            # 使用nameref引用当前节点的关联数组
            declare -n current_node="$node"
            # 处理空标签情况,将分号替换为空格
            current_node["$host"]=${tags//;/ }
        done
        
        rm -f "${node}_qemu.json"
    done
}

get_nodes
declare_variables
get_backupVMs

# 测试输出:打印第一个节点的VM标签(可选)
echo "=== 第一个节点的VM标签 ==="
declare -n test_node="${nodeArray[0]}"
for host in "${!test_node[@]}"; do
    echo "$host: ${test_node[$host]}"
done

关键修正点

  • 使用declare -n创建命名引用,实现对动态关联数组的赋值操作;
  • 简化jq调用逻辑,直接输出需要的字段,避免复杂的文本处理;
  • 移除冗余的引号转义,修复变量传递错误;
  • 补充Proxmox API地址的占位提示,避免无效请求;
  • 添加临时文件清理逻辑,避免残留垃圾文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 10:57:05