Pernyataan singkat pertanyaan:
Apakah ada metode bash bawaan untuk menghitung jumlah elemen dalam array bash, di mana nama array dinamis (mis. Disimpan dalam variabel), tanpa menggunakan salinan array penuh atau menggunakan eval
?
Informasi lebih lanjut:
Menggunakan substitusi parameter bash, seseorang dapat melakukan hal berikut:
- Menentukan panjang array:
myArr=(A B C); echo ${#myArr[@]}
. - Referensi tidak langsung variabel dengan nama:
NAME=myVar; echo ${!NAME}
(ini juga berlaku untuk elemen array):
NAME=myArr[1]; echo ${!NAME}
Tetapi jika nama array disimpan dalam variabel lain, bagaimana seseorang dapat menentukan jumlah elemen dalam array? (Orang mungkin menganggap ini kombinasi dari dua pergantian parameter di atas.) Misalnya:
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?
Di bawah ini adalah beberapa upaya yang semua GAGAL:
# 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
Saya juga sudah mencoba beberapa varian lain di atas, tetapi belum menemukan apa pun yang berfungsi tanpa: (A) membuat salinan array atau (B) dengan menggunakan eval
.
Metode kerja:
Ada beberapa cara untuk menyelesaikan ini yang mungkin tidak optimal (tapi perbaiki saya jika saya salah):
Metode 1: Salin Array
Tetapkan array ke variabel lain (bernama statis) dan dapatkan jumlah elemen di dalamnya.
EXPR=$NAME[@]
arrCopy=( "${!EXPR}" )
count=${#arrCopy}
Metode 2: Gunakan eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}'
eval $EXPR
# Now count is set to the length of the array
Ringkasan:
Apakah ada metode built-in (sintaks substitusi parameter) di bash untuk menentukan panjang array secara tidak langsung? Jika tidak, apa cara paling efisien untuk melakukan ini? Saya menganggap itu adalah eval
metode di atas, tetapi apakah ada masalah keamanan atau kinerja eval
?
time bash -c 'a=(1 a +); c=a; for ((i=0;i<100000;i++)); do eval "echo \${#$c[@]}"; done' > /dev/null
:, dan juga dengan e=$c[@]; d=("${!e}); echo ${#d[@]}
dalam lingkaran. Eval mengambil sekitar 90% dari waktu yang diambil dengan menyalin. Dan saya kira celah itu hanya akan meningkatkan array yang lebih besar dan elemen-elemennya.