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
?
sumber
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
:, dan juga dengane=$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.Jawaban:
Anda harus menangani hal-hal di indeks evals. dan Anda bisa secara tidak langsung melalui indeks variabel tipuan Anda jika Anda membuatnya menjadi array.
Karena
bash
indeks berbasis 0, jumlah total objek array akan selalu bekerja lebih dari satu indeks set tertinggi, jadi:... parameter diperluas ke kata default jika ada yang disediakan.
Jika tidak ada:
... tidak ada salahnya dilakukan.
Dalam loop saya melacak
$i
variabel ndex dan memeriksa apakah itu setidaknya sama besar dengan$c
ount. Ketika lebih rendah saya memperluas$r
eference var kea[i]
karena itu adalah indeks yang valid, tetapi ketika itu sama atau lebih besar saya memperluas$r
ef ke seluruh$a
rray.Ini dia dalam fungsi:
sumber
bash 4.3 nameref adalah anugerah. Namun, Anda dapat melakukan ini:
sumber