Vấn đề cơ bản ở đây là (các) nhà phát triển bash đã thiết kế / triển khai các mảng thực sự làm hỏng pooch. Họ quyết định rằng đó ${array}
chỉ là một bàn tay ngắn ${array[0]}
, đó là một sai lầm tồi tệ. Đặc biệt là khi bạn xem xét điều đó ${array[0]}
không có ý nghĩa và đánh giá chuỗi trống nếu kiểu mảng là kết hợp.
Việc gán một mảng có dạng array=(value1 ... valueN)
trong đó giá trị có cú pháp [subscript]=string
, do đó gán giá trị trực tiếp cho một chỉ mục cụ thể trong mảng. Điều này làm cho nó có thể có hai loại mảng, được lập chỉ mục số và băm được lập chỉ mục (được gọi là mảng kết hợp theo cách nói bash). Nó cũng làm cho nó để bạn có thể tạo các mảng được lập chỉ mục số thưa thớt. Rời khỏi [subscript]=
phần này là bàn tay ngắn cho một mảng được lập chỉ mục bằng số, bắt đầu với chỉ số thứ tự là 0 và tăng dần với mỗi giá trị mới trong câu lệnh gán.
Do đó, ${array}
nên đánh giá toàn bộ mảng, chỉ mục và tất cả. Nó nên đánh giá ngược lại với câu lệnh gán. Bất kỳ CS năm thứ ba chính cũng nên biết điều đó. Trong trường hợp đó, mã này sẽ hoạt động chính xác như bạn mong đợi:
declare -A foo bar
foo=${bar}
Sau đó, việc truyền các mảng theo giá trị cho các hàm và gán một mảng cho một mảng khác sẽ hoạt động khi phần còn lại của cú pháp shell ra lệnh. Nhưng vì họ đã không làm điều này đúng, toán tử gán =
không hoạt động cho các mảng và các mảng không thể được truyền theo giá trị cho các hàm hoặc cho các chuỗi con hoặc đầu ra nói chung ( echo ${array}
) mà không có mã để nhai hết tất cả.
Vì vậy, nếu nó đã được thực hiện đúng, thì ví dụ sau đây sẽ cho thấy mức độ hữu ích của mảng trong bash có thể tốt hơn đáng kể:
simple=(first=one second=2 third=3)
echo ${simple}
đầu ra kết quả phải là:
(first=one second=2 third=3)
Sau đó, các mảng có thể sử dụng toán tử gán và được truyền theo giá trị cho các hàm và thậm chí các tập lệnh shell khác. Dễ dàng lưu trữ bằng cách xuất ra một tệp và dễ dàng tải từ tệp vào tập lệnh.
declare -A foo
read foo <file
Than ôi, chúng tôi đã bị thất vọng bởi một nhóm phát triển bash siêu hạng khác.
Như vậy, để truyền một mảng cho một hàm, thực sự chỉ có một tùy chọn và đó là sử dụng tính năng nameref:
function funky() {
local -n ARR
ARR=$1
echo "indexes: ${!ARR[@]}"
echo "values: ${ARR[@]}"
}
declare -A HASH
HASH=([foo]=bar [zoom]=fast)
funky HASH # notice that I'm just passing the word 'HASH' to the function
sẽ dẫn đến kết quả đầu ra sau đây:
indexes: foo zoom
values: bar fast
Vì điều này được truyền bằng tham chiếu, bạn cũng có thể gán cho mảng trong hàm. Đúng, mảng được tham chiếu phải có phạm vi toàn cầu, nhưng đó không phải là vấn đề quá lớn, vì đây là kịch bản shell. Để truyền một mảng được lập chỉ mục liên kết hoặc thưa thớt theo giá trị cho một hàm đòi hỏi phải ném tất cả các chỉ mục và các giá trị vào danh sách đối số (không quá hữu ích nếu đó là một mảng lớn) như các chuỗi đơn như thế này:
funky "${!array[*]}" "${array[*]}"
và sau đó viết một loạt mã bên trong hàm để tập hợp lại mảng.