Phát biểu ngắn gọn của câu hỏi:
Có phương pháp bash tích hợp để đếm số phần tử trong mảng bash không, trong đó tên của mảng là động (tức là được lưu trữ trong một biến), mà không cần phải tạo một bản sao đầy đủ của mảng hoặc sử dụng eval
?
Thêm thông tin:
Sử dụng thay thế tham số bash, người ta có thể làm như sau:
- Xác định độ dài của một mảng :
myArr=(A B C); echo ${#myArr[@]}
. - Tham chiếu gián tiếp một biến theo tên:
NAME=myVar; echo ${!NAME}
(điều này cũng áp dụng cho các phần tử mảng):
NAME=myArr[1]; echo ${!NAME}
Nhưng nếu tên của một mảng được lưu trữ trong một biến khác, làm thế nào người ta có thể xác định số lượng phần tử trong mảng? (Người ta có thể coi đây là sự kết hợp của hai thay thế tham số ở trên.) Ví dụ:
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?
Dưới đây là nhiều nỗ lực mà tất cả 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
Tôi cũng đã thử một số biến thể khác ở trên, nhưng chưa tìm thấy bất cứ thứ gì hoạt động mà không có: (A) tạo một bản sao của mảng hoặc (B) bằng cách sử dụng eval
.
Các phương pháp làm việc:
Có một số cách giải quyết vấn đề này có thể không tối ưu (nhưng hãy sửa tôi nếu tôi sai):
Phương pháp 1: Sao chép Mảng
Gán mảng cho biến khác (được đặt tên tĩnh) và lấy số phần tử trong đó.
EXPR=$NAME[@]
arrCopy=( "${!EXPR}" )
count=${#arrCopy}
Cách 2: Sử dụng eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}'
eval $EXPR
# Now count is set to the length of the array
Tóm lược:
Có phương thức tích hợp nào (tức là cú pháp thay thế tham số) trong bash để xác định độ dài của một mảng một cách gián tiếp không? Nếu không, cách hiệu quả nhất để làm điều này là gì? Tôi giả sử đó là eval
phương pháp trên, nhưng có vấn đề về bảo mật hoặc hiệu suất eval
không?
time bash -c 'a=(1 a +); c=a; for ((i=0;i<100000;i++)); do eval "echo \${#$c[@]}"; done' > /dev/null
và tương tự như e=$c[@]; d=("${!e}); echo ${#d[@]}
trong vòng lặp. Eval mất khoảng 90% thời gian thực hiện bằng cách sao chép. Và tôi cho rằng khoảng cách sẽ chỉ tăng mảng lớn hơn và các phần tử của nó.