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
, es
hoặc fish
mả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ư ksh
trê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 bar
hoặc set -A array -- "$var" ...
nếu bạn không thể đảm bảo rằng $var
sẽ 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]=foo
sẽ 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ó 5
thể 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}" ]]
).
$a
cũ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.
pdksh
và các công cụ phái sinh (đó là cơ sở cho ksh
và đôi khi sh
củ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 ksh88
như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
mksh
tôi có một vài nhà khai thác thêm nguồn cảm hứng từ bash
, ksh93
hoặc zsh
như bài tập a la a=(x y)
, a+=(z)
, ${!a[@]}
để có được danh sách các chỉ số được giao.
zsh
. zsh
mảng thường được thiết kế tốt hơn và tận dụng tốt nhất ksh
và csh
mảng. Chúng tương tự ksh
như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
ksh
mô phỏng), phù hợp với mảng Bourne (tham số vị trí $ @, zsh
cũng hiển thị dưới dạng mảng $ argv) và csh
mả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.
$a
khô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]=1
hoạ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 y
cũng hoạt động, nhưng set -A a -- x y
khô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/sh
vỏ POSIX vẫn dựa trên ksh88
) và ksh
củ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
. bash
là vỏ của dự án GNU. Nó được sử dụng như sh
trê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. bash
mảng chủ yếu mô phỏng ksh88
những cái có một số tính năng của ksh93
và 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ừ ksh93
và zsh
.
- các
bash
phiê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
array
nộ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 perl
hoặ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 zsh
các mảng giống như ksh
cá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 ksh
cá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 yash
và ksh88
và các phiên bản cũ của pdksh
cá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 zsh
người dùng vẫn sử dụng mảng của mình thông thường theo cách zsh.