使用变量向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
错误原因分析
- 动态关联数组赋值语法错误:
$node[$host]=$tags是错误写法,Bash会把这个表达式解析为执行一个名为$node[$host]的命令,而非数组赋值操作。要操作动态命名的关联数组,需要用**命名引用(nameref)**来间接引用数组。 - 冗余的字符串转义:
脚本中多处出现\"${nodeArray[@]}\"这种写法,转义引号会导致变量被包裹在引号中,后续curl请求和jq解析会出现无效参数问题。 - jq表达式不规范:
jq的查询表达式需要用单引号包裹,比如jq '[.data[].node]' nodes,否则Shell会解析方括号等特殊字符,导致jq执行出错。 - 数据提取逻辑冗余:
用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
相关产品推荐
相关产品推荐

