Krótkie wyjaśnienie pytania:
Czy istnieje wbudowana metoda bash zliczająca liczbę elementów w tablicy bash, w której nazwa tablicy jest dynamiczna (tj. Przechowywana w zmiennej), bez uciekania się do wykonania pełnej kopii tablicy lub użycia eval
?
Więcej informacji:
Używając podstawiania parametrów bash, można wykonać następujące czynności:
- Określić długość tablicy:
myArr=(A B C); echo ${#myArr[@]}
. - Pośrednio odwołuje się do zmiennej według nazwy:
NAME=myVar; echo ${!NAME}
(dotyczy to również elementów tablicy):
NAME=myArr[1]; echo ${!NAME}
Ale jeśli nazwa tablicy jest przechowywana w innej zmiennej, w jaki sposób można określić liczbę elementów w tablicy? (Można to uznać za kombinację powyższych dwóch podstawień parametrów.) Na przykład:
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?
Poniżej znajduje się wiele prób, które wszystkie FAIL:
# 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
Próbowałem także innych wariantów powyższego, ale nie znalazłem jeszcze niczego, co działałoby bez: (A) wykonania kopii tablicy lub (B) przy użyciu eval
.
Metody pracy:
Istnieje kilka sposobów rozwiązania tego problemu, które prawdopodobnie nie są optymalne (ale popraw mnie, jeśli się mylę):
Metoda 1: Skopiuj tablicę
Przypisz tablicę do innej (statycznie nazwanej) zmiennej i uzyskaj w niej liczbę elementów.
EXPR=$NAME[@]
arrCopy=( "${!EXPR}" )
count=${#arrCopy}
Metoda 2: Użyj eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}'
eval $EXPR
# Now count is set to the length of the array
Podsumowanie:
Czy istnieje jakaś wbudowana metoda (tj. Składnia podstawiania parametrów) w bash do pośredniego określania długości tablicy? Jeśli nie, jaki jest najbardziej efektywny sposób? Zakładam, że jest to eval
powyższa metoda, ale czy występują problemy z bezpieczeństwem lub wydajnością eval
?
źródło
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
i podobnie ze=$c[@]; d=("${!e}); echo ${#d[@]}
pętlą. Kopiowanie zajęło około 90% czasu. I przypuszczam, że odstęp zwiększy tylko większy rozmiar tablicy i jej elementów.Odpowiedzi:
powinieneś sobie z tym poradzić w ewaluacjach indeksu. i możesz pośrednio poprzez indeksy zmiennej pośredniej, jeśli utworzysz z niej tablicę.
Ponieważ
bash
indeksy są oparte na 0, całkowita liczba obiektów tablicowych zawsze będzie działać do jednego więcej niż najwyższy ustawiony indeks, a zatem:... parametr jest interpretowany jako domyślny wyraz, jeśli taki istnieje.
Jeśli nie zostanie dostarczony:
... nic złego się nie stanie.
W pętli
$i
śledzę zmienną ndex i sprawdzam, czy jest ona co najmniej tak duża jak$c
ount. Kiedy jest mniejszy, rozwijam$r
eferencję var,a[i]
ponieważ jest to poprawny indeks, ale kiedy jest równy lub większy, rozszerzam$r
ef do całej$a
tablicy.Oto funkcja:
źródło
Nazwy plików bash 4.3 są darem niebios. Możesz to jednak zrobić:
źródło