Короткий виклад питання:
Чи існує вбудований метод 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
?
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% часу, який займає копіювання. І я припускаю, що розрив лише збільшить більший масив та його елементи.