ассоциативные массивы bash — переменная, содержащая пару значений

У меня есть файл, который выглядит так:

stringtests (6 tests)
alphatests (1 tests)
arraytests (100 tests)

Я могу извлечь и перевести в:

["stringtests"]="6"
["alphatests"]="1"
["arraytests"]="100"

Я помещаю их в переменную («тесты»):

~> tests="[\"stringtests\"]=\"6\" [\"alphatests\"]=\"1\" [\"arraytests\"]=\"100\""

Потом пытаюсь поместить их в ассоциативный массив с помощью переменной получаю ошибку:

~> declare -A arr=( $tests )
-bash: arr: ["stringtests"]="6": must use subscript when assigning associative array
-bash: arr: ["alphatests"]="1": must use subscript when assigning associative array
-bash: arr: ["arraytests"]="100": must use subscript when assigning associative array

"eval" тоже не работает:

declare -A arr=( $(eval echo $tests) )
-bash: arr: [stringtests]=6: must use subscript when assigning associative array
-bash: arr: [alphatests]=1: must use subscript when assigning associative array
-bash: arr: [arraytests]=100: must use subscript when assigning associative array

Но если я поставлю значения напрямую, это сработает:

~> declare -A arr=( ["stringtests"]="6" ["alphatests"]="1" ["arraytests"]="100" )
~> echo ${arr[@]}
1 100 6
~> echo ${!arr[@]}
alphatests arraytests stringtests

Возможно ли это сделать?


person Sean Walton    schedule 31.10.2017    source источник
comment
Нужно eval перед объявлением не в подоболочке.eval declare -A arr=( $tests ). Сбой, потому что = оценивается до расширения переменной, поэтому массив видит ["stringtests"]="6" как одну строку.   -  person 123    schedule 31.10.2017
comment
@123, а? eval здесь можно полностью избежать, а когда его можно избежать, его следует.   -  person Charles Duffy    schedule 31.10.2017
comment
@CharlesDuffy Просто указал на проблему с их командой, не предполагая, что это лучший вариант.   -  person 123    schedule 31.10.2017


Ответы (2)


Заменять

declare -A arr=( $tests )

с

declare -A arr='('$tests')'

tests="[\"stringtests\"]=\"6\" [\"alphatests\"]=\"1\" [\"arraytests\"]=\"100\""
declare -A arr='('$tests')'
declare -p arr

Выход:

declare -A arr='([alphatests]="1" [arraytests]="100" [stringtests]="6" )'
person Cyrus    schedule 31.10.2017
comment
вероятно, безопаснее написать declare -A arr="($tests)", чтобы переменная была заключена в кавычки. - person glenn jackman; 31.10.2017
comment
@Cyrus Как экранирование/цитирование скобок заставляет по-разному интерпретировать содержимое? Есть ли какая-либо документация или я упускаю что-то очевидное? - person 123; 31.10.2017
comment
@123: Мне неизвестны подробности. - person Cyrus; 31.10.2017
comment
@Cyrus Ты только что наткнулся на это тогда? Я не понимаю, почему это имеет какое-то значение. Почему = интерпретируется только в том случае, если () экранированы? - person 123; 31.10.2017
comment
@123: Я наткнулся на это, когда смотрел на вывод: declare -p arr. - person Cyrus; 31.10.2017
comment
@ Сайрус, честно! - person 123; 31.10.2017

Я бы вообще избегал переменной temp и заполнил массив, пока вы анализируете файл

declare -A arr
while IFS= read -r line; do 
    # bash regex: the literal bits are quoted
    if [[ $line =~ (.+)" ("([0-9]+) ]]; then 
        arr["${BASH_REMATCH[1]}"]="${BASH_REMATCH[2]}"
    fi
done < file
declare -p arr
declare -A arr='([alphatests]="1" [arraytests]="100" [stringtests]="6" )'
person glenn jackman    schedule 31.10.2017