Попытка создать динамический набор пар ключ-значение с помощью серии циклов 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





Сначала нужно объявить ассоциативный массив:
declare -A array
В задании не используйте знак доллара слева:
array[$key]=$value
Кроме того, убедитесь, что вы запускаете скрипт в bash, а не в какой-либо другой оболочке. Ассоциативные массивы поддерживаются не везде (например, в dash).
Я предлагаю использовать двойные кавычки: array[$key] = "$value"
@Cyrus: они не нужны в заданиях.
Вы правы, спасибо, что указали на это.
@choroba Массивы объявляются в скрипте ранее на основе содержимого другого цикла. Имя самого массива является переменной в цикле for, таким образом, $ в массиве $. Есть ли лучший способ зацикливания и добавления в массив в качестве переменной?
Соответствующая часть вашего кода в основном:
for node in "${nodeArray[@]}"; do
declare -A $node
done
for node in "${nodeArray[@]}"; do
$node[$host]=$tags
done
Bash не поддерживает косвенное обращение к имени переменной, написанное таким образом.
Присваивания распознаются только в том случае, если LHS является допустимым именем переменной, за которым может следовать что-то в скобках, за которым следует знак равенства, за которым следует присваиваемое значение. Однако $node перед расширением не является допустимым именем переменной. (См.: присваивание() в исходном коде Bash.)
Поскольку Bash не распознает ваше присваивание как единицу, он пытается выполнить слово как команду, что приводит к ошибкам, которые вы видели.
Почти наверняка есть лучший способ структурировать логику вашего кода, чтобы этот тип косвенности не требовался, но быстрое и грязное решение — использовать nameref во втором цикле (первый цикл остается неизменным) :
for node in "${nodeArray[@]}"; do
declare -n ref=$node
ref[$host]=$tags
done
Кажется, это, по крайней мере, избавило от ошибок, однако, похоже, он не создает нужный мне вывод, по-видимому, меняясь каждый раз, когда скрипт запускается, когда я делаю быстрый echo ${foo[@]}, где foo - известное имя узла, созданное declare -n ref-$node Похоже, мне все-таки придется найти лучшую структуру для логики. Если есть какие-либо предложения о том, с чего начать искать или читать о лучшем способе сделать это, я всегда ценю хороший толчок в правильном направлении.
@DavisSayer Я полагаю ref-$node это опечатка? Обратите внимание, что вы должны выполнять declare -n каждый раз, когда вы меняете место назначения ссылки - оно должно быть внутри цикла.
Ах, да, это должно было читаться ref=$node, и оно объявляется в начале цикла for node in "${nodeArray[@]}" — в основном я удалил функцию declare_variables из скрипта и интегрировал nameref в начало функции get_backupVMs.
@DavisSayer Я ожидал, что вы сохраните первый цикл for без изменений (я исключил его, чтобы сосредоточиться на изменении). Вам все еще нужно declare -A ваши фактические ассоциативные массивы, иначе присваивание ref[$host] будет рассматриваться как применение к индексированному массиву, а $host будет приведено к целому числу.
Я думаю, вам нужен псевдомногомерный массив (поскольку bash поддерживает только одно измерение, вам нужно создать специальные ключи)
declare -A array
for n in ${nodeArray[@]}; do
for h in ${hosts[@]}; do
array["$n,$h"] = "tags $n $h"
done
done
Уберите $ перед
array.$— специальный символ оболочки, указывающий на расширение параметра. Когда вы начинаете строку с $, первое слово никогда не интерпретируется как присваивание переменной, а как команда. Вот почему вы получаете ошибку, команда не найдена.