Как перебрать массив, используя косвенную ссылку?

Как я могу заставить этот код работать?

#!/bin/bash
ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )
for FRUIT in ${!ARRAYNAME[@]}
do
    echo ${FRUIT}
done

Этот код:

echo ${!ARRAYNAME[0]}

ПечатьAPPLE, Я пытаюсь сделать что-то похожее, но с & quot; [@] & quot; перебирать массив.

Заранее спасибо,

 Dennis Williamson24 июн. 2012 г., 22:27
Посмотри пожалуйстаBashFAQ/006.

Ответы на вопрос(5)

eval выполняет код, содержащий элементы массива, даже если они содержат, например, подстановки команд. Он также изменяет элементы массива, интерпретируя в них метасимволы bash.

Инструментом, который позволяет избежать этих проблем, являетсяdeclare reference, увидетьman bash под объявить:

-n Give each name the nameref attribute, making it a name reference to another variable. That other variable is defined by the value of name. All references, assignments, and attribute modifications to name, except those using or changing the -n attribute itself, are performed on the variable referenced by name's value. The nameref attribute cannot be applied to array variables.

#!/bin/bash
declare -n ARRAYNAME='FRUITS'
FRUITS=(APPLE BANANA ORANGE "BITTER LEMON")
for FRUIT in "${ARRAYNAME[@]}"
do
    echo "${FRUIT}"
done
 18 нояб. 2018 г., 02:47
Спасибо. В настоящее время, используя Bash 4.3+, это кажется лучшим и самым простым ответом. Следует проголосовать за верх. Обратите внимание, что предложение в документе "атрибут nameref не может быть применено к переменным массива", сбивает с толку и, возможно, вводит в заблуждение, поскольку может показаться, что его нельзя использовать для доступа к переменным массива. Однако на самом деле это работает.

эти ответы не будут масштабироваться для наиболее распространенных, реальных вариантов использования, то есть элементов массива, содержащих пробелы или подстановочные знаки, которые еще не следует расширять до имен файлов.

FRUITS=( APPLE BANANA ORANGE 'not broken' '*.h')
ARRAYNAME=FRUITS
eval ARRAY=\(\${$ARRAYNAME[@]}\)

$ echo "${ARRAY[4]}"
broken
$ echo "${ARRAY[5]}"
config.h
$

Это работает:

FRUITS=( APPLE BANANA ORANGE 'not broken' '*.h')
ARRAYNAME=FRUITS
eval ARRAY="(\"\${$ARRAYNAME[@]}\")"

$ echo "${ARRAY[3]}"
not broken
$ echo "${ARRAY[4]}"
*.h
$

Just as you should get in the habit of using "[email protected]" not [email protected], always quote inside ( ) for array expansions, unless you want filename expansion or know there's no possibility of array elements containing whitespace.

Do this: X=("${Y[@]}")

Not this: X=(${Y[@]})

УвидетьBash trick #2 описано здесь: http://mywiki.wooledge.org/BashFAQ/006

Кажется, работает в Bash 3 и выше.

#!/bin/bash

ARRAYNAME='FRUITS'
tmp=$ARRAYNAME[@]
FRUITS=( APPLE BANANA ORANGE "STAR FRUIT" )
for FRUIT in "${!tmp}"
do
    echo "${FRUIT}"
done

Вот более реалистичный пример, показывающий, как передать массив по ссылке на функцию:

pretty_print_array () {
  local arrayname=$1
  local tmp=$arrayname[@]
  local array=( "${!tmp}" )
  local FS=', ' # Field seperator
  local var
  # Print each element enclosed in quotes and separated by $FS
  printf -v var "\"%s\"$FS" "${array[@]}"
  # Chop trailing $FS
  var=${var%$FS}
  echo "$arrayname=($var)"
}
FRUITS=( APPLE BANANA ORANGE "STAR FRUIT" )
pretty_print_array FRUITS
# prints FRUITS=("APPLE", "BANANA", "ORANGE", "STAR FRUIT")
 06 мая 2016 г., 01:48
любой способ получить размер такого косвенного массива без Eval тоже?

ал в Интернете решение другой, но связанной проблемы

ARRAYNAME=( FRUITS VEG )
FRUITS=( APPLE BANANA ORANGE )
VEG=( CARROT CELERY CUCUMBER )
for I in "${ARRAYNAME[@]}"
do
    array="${I}[@]"
    for fruit in "${!array}"; do
        echo $fruit
    done
done
 16 февр. 2018 г., 15:32
array="${I}[@]"  точно так же, какtmp=$arrayname[@]! Там нет улучшения!
Решение Вопроса

${!ARRAYNAME[@]} означает "индексыARRAYNAME& Quot ;. Как указано встраница руководства bash посколькуARRAYNAME устанавливается, но как строка, а не как массив, возвращает0.

Вот решение с использованиемeval.

#!/usr/bin/env bash

ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )

eval array=\( \${${ARRAYNAME}[@]} \)

for fruit in "${array[@]}"; do
  echo ${fruit}
done

То, что вы изначально пытались сделать, это создатьКосвенная ссылка, Они были введены в bash версии 2 и должны были в значительной степени заменить необходимостьeval при попытке добиться подобного отражению поведения в оболочке.

Что вы должны сделать при использовании косвенных ссылок с массивами, это включить[@] по вашему предположению на имя переменной:

#!/usr/bin/env bash

ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )

array="${ARRAYNAME}[@]"
for fruit in "${!array}"; do
  echo $fruit
done

Все это говорит об использовании косвенных ссылок в этом тривиальном примере, но, как указано в ссылке, предоставленной Деннисом Уильямсоном, вам не следует использовать их в реальных сценариях. Они гарантированно сделают ваш код более запутанным, чем необходимо. Обычно вы можете получить необходимую вам функциональность с помощью ассоциативного массива.

 24 июн. 2012 г., 22:42
@Neuquino Смотрите мой отредактированный ответ. Все, что вам нужно сделать, это объединить[@] в конце вашей входной переменной.
 Neuquino24 июн. 2012 г., 22:38
Тим: твоя вторая часть ответа бесполезна, потому что ARRAYNAME является входным параметром моего скрипта. Но ваше первое решение позволило мне найти более элегантное решение: ARRAY = $ {! ARRAYNAME}; за фрукты в $ {ARRAY [@]} ... Спасибо
 Neuquino19 июл. 2012 г., 17:37
@ormaaj ARRAYNAME не является входным параметром. У меня есть файл конфигурации (config.conf) с KEYS = (FRUITS VEGETABLES MEAT), а затем несколько строк с фруктами = (APPLE BANANA ORANGE) \ n VEGETABLES = (BEANS LETTUCE) \ n MEAT = (CHICKEN ROAST_BEAF). Затем в моем скрипте я делаю исходный файл config.conf.
 04 июл. 2012 г., 13:30
@Neuquino Если ARRAYNAME является входным параметром для вашего сценария, вы делаете что-то ужасно неправильное. Нет никаких причин смешивать пользовательский ввод с именами переменных. В этом случае (в сочетании с косвенным расширением) это позволяет произвольное внедрение кода. ЕДИНСТВЕННАЯ веская причина для этих методов для использования в функциях, никогда в глобальной области и никогда не объединяется с пользовательским вводом.
 19 июл. 2012 г., 19:21
@Neuquino Должно быть в порядке, если вы можете доверять вводу (файл в данном случае).

Ваш ответ на вопрос