Краткое изложение вопроса:
Существует ли встроенный метод bash для подсчета количества элементов в массиве bash, где имя массива является динамическим (т.е. хранится в переменной), не прибегая к созданию полной копии массива или его использованию eval
?
Дополнительная информация:
Используя подстановку параметров bash, можно сделать следующее:
- Определить длину массива:
myArr=(A B C); echo ${#myArr[@]}
. - Косвенная ссылка на переменную по имени:
NAME=myVar; echo ${!NAME}
(это также относится к элементам массива):
NAME=myArr[1]; echo ${!NAME}
Но если имя массива хранится в другой переменной, как можно определить количество элементов в массиве? (Можно рассматривать это как комбинацию двух приведенных выше подстановок параметров.) Например:
myArr=(A B C D)
NAME=myArr
# Get the number of elements in the array indirectly referenced by NAME.
count=${#$NAME[@]} # This syntax is invalid. What is the right way?
Ниже приведены несколько попыток, которые все НЕУДАЧИ:
# Setup for following attempts:
myArr=(A B C D)
NAME=myArr
EXPR1=$NAME[@] # i.e. EXPR1='myArr[@]'
EXPR2=#$NAME[@] # i.e. EXPR2='#myArr[@]'
# Failed attempts to get the lengh of the array indirectly:
1. count=${#$NAME[@]} # ERROR: bash: ...: bad substitution
2. count=${#!EXPR1} # ERROR: bash: !EXPR}: event not found
3. count=${#\!EXPR1} # ERROR: bash: ...: bad substitution
4. count=${!#EXPR1} # ERROR: bash: ...: bad substitution
5. count=${!EXPR2} # Returns NULL
Я также попробовал некоторые другие варианты вышеупомянутого, но еще не нашел ничего, что работает без: (A) создания копии массива или (B) с помощью eval
.
Методы работы:
Есть несколько способов решения этой проблемы, которые, вероятно, не оптимальны (но исправьте меня, если я ошибаюсь):
Способ 1: скопировать массив
Присвойте массив другой переменной (со статическим именем) и получите количество элементов в нем.
EXPR=$NAME[@]
arrCopy=( "${!EXPR}" )
count=${#arrCopy}
Способ 2: использование eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}'
eval $EXPR
# Now count is set to the length of the array
Резюме:
Есть ли в bash встроенный метод (т. Е. Синтаксис подстановки параметров) для косвенного определения длины массива? Если нет, то какой самый эффективный способ сделать это? Я предполагаю, что это eval
метод выше, но есть проблемы с безопасностью или производительностью eval
?
источник
bash
namerefs? ,declare -n ref=abc; abc=(A B C D); printf '%s\n' "${ref[@]}"
time bash -c 'a=(1 a +); c=a; for ((i=0;i<100000;i++)); do eval "echo \${#$c[@]}"; done' > /dev/null
и аналогично сe=$c[@]; d=("${!e}); echo ${#d[@]}
циклом. Эвал занимал около 90% времени, затрачиваемого на копирование. И я полагаю, что разрыв будет только увеличиваться, чем больше массив и его элементы.Ответы:
вы должны справиться с этим в индексе evals. и вы можете выполнять косвенные действия через индексы вашей косвенной переменной, если вы сделаете ее массивом.
Поскольку
bash
индексы основаны на 0, общее количество объектов массива всегда будет на единицу больше, чем индекс с наибольшим набором, и поэтому:... параметр расширяется до слова по умолчанию, если оно есть.
Если один не предоставлен:
... нет никакого вреда
В цикле я отслеживаю
$i
переменную ndex и проверяю, не меньше ли она размера$c
ount. Когда оно меньше, я расширяю$r
переменную var до,a[i]
потому что это допустимый индекс, но когда он равен или больше, я расширяю$r
ef на весь$a
массив.Вот это в функции:
источник
bash 4.3 nameref являются находкой. Тем не менее, вы можете сделать это:
источник