Giả sử bạn muốn hạn chế để Bourne giống như vỏ (nhiều tiện ích khác như csh, tcsh, rc, eshoặc fishmảng hỗ trợ nhưng viết một kịch bản tương thích cùng một lúc để Bourne giống như vỏ và những người là phức tạp và thường vô nghĩa vì họ là thông dịch viên cho hoàn toàn khác nhau và ngôn ngữ không tương thích), lưu ý rằng có sự khác biệt đáng kể giữa các lần thực hiện.
Bourne giống như các shell hỗ trợ các mảng là:
ksh88(đó là mảng đầu tiên triển khai, ksh88 vẫn được tìm thấy như kshtrên hầu hết các Unice thương mại truyền thống, nơi nó cũng là cơ sở cho sh)
- mảng là một chiều
- Mảng được định nghĩa là
set -A array foo barhoặc set -A array -- "$var" ...nếu bạn không thể đảm bảo rằng $varsẽ không bắt đầu bằng -hoặc +.
- Chỉ số mảng bắt đầu tại
0.
- Các phần tử mảng riêng lẻ được gán là
a[1]=value.
- mảng thì thưa thớt. Đó là
a[5]=foosẽ hoạt động ngay cả khi a[0,1,2,3,4]không được thiết lập và sẽ khiến chúng không được đặt.
${a[5]}để truy cập phần tử của chỉ số 5 (không nhất thiết là phần tử thứ 6 nếu mảng thưa thớt). Có 5thể có bất kỳ biểu thức số học.
- kích thước mảng và chỉ mục được giới hạn (đến 4096).
${#a[@]} là số phần tử được gán trong mảng (không phải là chỉ số được gán lớn nhất).
- không có cách nào để biết danh sách các mục con được chỉ định (ngoài việc kiểm tra 4096 phần tử riêng lẻ với
[[ -n "${a[i]+set}" ]]).
$acũng giống như ${a[0]}. Đó là mảng bằng cách nào đó mở rộng các biến vô hướng bằng cách cung cấp cho chúng các giá trị bổ sung.
pdkshvà các công cụ phái sinh (đó là cơ sở cho kshvà đôi khi shcủa một số BSD và là triển khai ksh mã nguồn mở duy nhất trước khi nguồn ksh93 được giải phóng):
Chủ yếu là thích ksh88nhưng lưu ý:
- Một số triển khai cũ không hỗ trợ
set -A array -- foo bar, ( --không cần thiết ở đó).
${#a[@]}là một cộng với chỉ số của chỉ số được gán lớn nhất. ( a[1000]=1; echo "${#a[@]}"xuất ra 1001 mặc dù mảng chỉ có một phần tử.
- trong các phiên bản mới hơn, kích thước mảng không còn bị giới hạn (ngoài kích thước của số nguyên).
- phiên bản gần đây của
mkshtôi có một vài nhà khai thác thêm nguồn cảm hứng từ bash, ksh93hoặc zshnhư bài tập a la a=(x y), a+=(z), ${!a[@]}để có được danh sách các chỉ số được giao.
zsh. zshmảng thường được thiết kế tốt hơn và tận dụng tốt nhất kshvà cshmảng. Chúng tương tự kshnhưng có sự khác biệt đáng kể:
- các chỉ số bắt đầu từ 1, không phải 0 (ngoại trừ trong
kshmô phỏng), phù hợp với mảng Bourne (tham số vị trí $ @, zshcũng hiển thị dưới dạng mảng $ argv) và cshmảng.
- chúng là một loại riêng biệt từ các biến bình thường / vô hướng. Các nhà khai thác áp dụng khác nhau cho họ và như bạn thường mong đợi.
$akhông giống như ${a[0]}nhưng mở rộng ra các phần tử không trống của mảng ( "${a[@]}"cho tất cả các phần tử như trong ksh).
- chúng là các mảng bình thường, không phải là các mảng thưa thớt.
a[5]=1hoạt động nhưng gán tất cả các phần tử từ 1 đến 4 chuỗi trống nếu chúng không được gán. Vì vậy ${#a[@]}(giống như ${#a}trong ksh là kích thước của phần tử của chỉ số 0) là số phần tử trong mảng và chỉ số được gán lớn nhất.
- mảng kết hợp được hỗ trợ.
- một số lượng lớn các toán tử để làm việc với các mảng được hỗ trợ, quá lớn để liệt kê ở đây.
- mảng được định nghĩa là
a=(x y). set -A a x ycũng hoạt động, nhưng set -A a -- x ykhông được hỗ trợ trừ khi trong mô phỏng ksh ( --không cần thiết trong mô phỏng zsh).
ksh93. (ở đây mô tả các phiên bản mới nhất). ksh93, từ lâu được coi là thử nghiệm có thể được tìm thấy trong ngày càng nhiều hệ thống mà nó đã được phát hành dưới dạng FOSS. Chẳng hạn, đó là /bin/sh(nơi nó thay thế vỏ Bourne, /usr/xpg4/bin/shvỏ POSIX vẫn dựa trên ksh88) và kshcủa Solaris 11. Mảng của nó mở rộng và tăng cường ksh88.
a=(x y)có thể được sử dụng để định nghĩa một mảng, nhưng vì a=(...)cũng được sử dụng để xác định các biến hỗn hợp ( a=(foo=bar bar=baz)), a=()không rõ ràng và khai báo một biến ghép, không phải là một mảng.
- mảng là đa chiều (
a=((0 1) (0 2))) và các phần tử mảng cũng có thể là biến tổng hợp ( a=((a b) (c=d d=f)); echo "${a[1].c}").
- Một
a=([2]=foo [5]=bar)cú pháp có thể được sử dụng để xác định các mảng thưa thớt cùng một lúc.
- Hạn chế kích thước nâng.
- Không đến mức
zsh, nhưng số lượng lớn các nhà khai thác cũng hỗ trợ để thao tác các mảng.
"${!a[@]}" để lấy danh sách các chỉ số mảng.
- mảng kết hợp cũng được hỗ trợ như một loại riêng biệt.
bash. bashlà vỏ của dự án GNU. Nó được sử dụng như shtrên các phiên bản gần đây của OS / X và một số bản phân phối GNU / Linux. bashmảng chủ yếu mô phỏng ksh88những cái có một số tính năng của ksh93và zsh.
a=(x y)được hỗ trợ. set -A a x y không được hỗ trợ. a=()tạo một mảng trống (không có biến ghép trong bash).
"${!a[@]}" cho danh sách các chỉ số.
a=([foo]=bar)cú pháp được hỗ trợ cũng như một vài người khác từ ksh93và zsh.
- các
bashphiên bản gần đây cũng hỗ trợ các mảng kết hợp như một loại riêng biệt.
yash. Đây là một triển khai POSIX sh nhận biết nhiều byte tương đối gần đây. Không sử dụng rộng rãi. Mảng của nó là một API sạch khác tương tự nhưzsh
- mảng không thưa thớt
- Chỉ số mảng bắt đầu từ 1
- được định nghĩa (và khai báo) với
a=(var value)
- các phần tử được chèn, xóa hoặc sửa đổi với
arraynội dung
array -s a 5 valueđể sửa đổi phần tử thứ 5 sẽ thất bại nếu phần tử đó không được gán trước.
- số phần tử trong mảng là
${a[#]}, ${#a[@]}là kích thước của các yếu tố như một danh sách.
- mảng là một loại riêng biệt. Bạn cần
a=("$a")xác định lại một biến vô hướng dưới dạng một mảng trước khi bạn có thể thêm hoặc sửa đổi các phần tử.
- mảng không được hỗ trợ khi được gọi là
sh.
Vì vậy, từ đó bạn có thể thấy rằng việc phát hiện hỗ trợ mảng, điều bạn có thể làm với:
if (unset a; set -A a a; eval "a=(a b)"; eval '[ -n "${a[1]}" ]'
) > /dev/null 2>&1
then
array_supported=true
else
array_supported=false
fi
là không đủ để có thể sử dụng các mảng đó. Bạn cần xác định các lệnh bao bọc để gán các mảng như là toàn bộ và các phần tử riêng lẻ và đảm bảo rằng bạn không cố gắng tạo các mảng thưa thớt.
Giống
unset a
array_elements() { eval "REPLY=\"\${#$1[@]}\""; }
if (set -A a -- a) 2> /dev/null; then
set -A a -- a b
case ${a[0]}${a[1]} in
--) set_array() { eval "shift; set -A $1"' "$@"'; }
set_array_element() { eval "$1[1+(\$2)]=\$3"; }
first_indice=0;;
a) set_array() { eval "shift; set -A $1"' -- "$@"'; }
set_array_element() { eval "$1[1+(\$2)]=\$3"; }
first_indice=1;;
--a) set_array() { eval "shift; set -A $1"' "$@"'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0;;
ab) set_array() { eval "shift; set -A $1"' -- "$@"'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0;;
esac
elif (eval 'a[5]=x') 2> /dev/null; then
set_array() { eval "shift; $1=("'"$@")'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0
elif (eval 'a=(x) && array -s a 1 y && [ "${a[1]}" = y ]') 2> /dev/null; then
set_array() { eval "shift; $1=("'"$@")'; }
set_array_element() {
eval "
$1=(\${$1+\"\${$1[@]}"'"})
while [ "$(($2))" -ge "${'"$1"'[#]}" ]; do
array -i "$1" "$2" ""
done'
array -s -- "$1" "$((1+$2))" "$3"
}
array_elements() { eval "REPLY=\${$1[#]}"; }
first_indice=1
else
echo >&2 "Array not supported"
fi
Và sau đó bạn truy cập vào các phần tử mảng với "${a[$first_indice+n]}", the whole list với "${a[@]}"và sử dụng các chức năng wrapper ( array_elements, set_array, set_array_element) để có được số phần tử của một mảng (trong $REPLY), thiết lập các mảng như toàn bộ hoặc assign một yếu tố cá nhân.
Có lẽ không đáng để nỗ lực. Tôi sẽ sử dụng perlhoặc giới hạn đối với mảng shell Bourne / POSIX : "$@".
Nếu mục đích là để một số tệp có nguồn gốc từ vỏ tương tác của người dùng để xác định các hàm sử dụng nội bộ mảng, thì đây là một vài lưu ý có thể hữu ích.
Bạn có thể định cấu hình zshcác mảng giống như kshcác mảng trong phạm vi cục bộ (trong các hàm hoặc hàm ẩn danh).
myfunction() {
[ -z "$ZSH_VERSION" ] || setopt localoption ksharrays
# use arrays of indice 0 in this function
}
Bạn cũng có thể mô phỏng ksh(cải thiện khả năng tương thích với kshcác mảng và một số khu vực khác) với:
myfunction() {
[ -z "$ZSH_VERSION" ] || emulate -L ksh
# ksh code more likely to work here
}
Với ý nghĩ đó và bạn sẵn sàng thả hỗ trợ cho yashvà ksh88và các phiên bản cũ của pdkshcác dẫn xuất, và miễn là bạn không cố gắng tạo ra các mảng thưa thớt, bạn sẽ có thể liên tục sử dụng:
a[0]=foo
a=(foo bar)(nhưng không a=())
"${a[#]}", "${a[@]}","${a[0]}"
trong các chức năng có emulate -L ksh, trong khi zshngười dùng vẫn sử dụng mảng của mình thông thường theo cách zsh.