Предполагая , что вы хотите ограничиться Bourne-подобных оболочкам (много других раковин любят csh
, tcsh
, rc
, es
или fish
поддержку массивы , но написание сценария совместимы в то же время Bourne-подобные оболочкам и тем сложно и вообще бессмысленно , поскольку они интерпретаторы совершенно разные и несовместимые языки), обратите внимание, что между реализациями есть существенные различия.
Оболочкам Борна, которые поддерживают массивы, являются:
ksh88
(это первый, реализующий массивы, ksh88 все еще встречается как ksh
в большинстве традиционных коммерческих Unix-систем, где он также является основой sh
)
- массивы одномерные
- Массивы определяются как
set -A array foo bar
или set -A array -- "$var" ...
если вы не можете гарантировать, что $var
они не начнутся с -
или +
.
- Индексы массива начинаются с
0
.
- Отдельные элементы массива назначаются как
a[1]=value
.
- массивы редки. То есть
a[5]=foo
будет работать, даже если a[0,1,2,3,4]
они не установлены и оставят их неустановленными.
${a[5]}
получить доступ к элементу индекса 5 (необязательно к 6-му элементу, если массив разрежен). Здесь 5
может быть любое арифметическое выражение.
- Размер массива и индекс ограничены (до 4096).
${#a[@]}
номер назначенного элемента в массиве (не самый большой назначенный индекс).
- нет способа узнать список назначенных подписчиков (кроме как индивидуально проверить элементы 4096
[[ -n "${a[i]+set}" ]]
).
$a
так же, как ${a[0]}
. То есть массивы как-то расширяют скалярные переменные, давая им дополнительные значения.
pdksh
и производные (это основа ksh
и иногда sh
несколько BSD, и это была единственная реализация ksh с открытым исходным кодом до освобождения источника ksh93):
В основном нравится, ksh88
но обратите внимание:
- Некоторые старые реализации не поддерживали
set -A array -- foo bar
(там --
не было необходимости).
${#a[@]}
это один плюс индекс наибольшего назначенного индекса. ( a[1000]=1; echo "${#a[@]}"
выводит 1001, хотя массив имеет только один элемент.
- в более новых версиях размер массива больше не ограничен (кроме размера целых чисел).
- последние версии
mksh
есть несколько дополнительных операторов , вдохновленных из bash
, ksh93
или zsh
как задания а - ля a=(x y)
, a+=(z)
, ${!a[@]}
чтобы получить список назначенных индексов.
zsh
, zsh
массивы , как правило , лучше разработаны и взять лучшее из ksh
и csh
массивов. Они похожи, ksh
но со значительными различиями:
- Индексы начинаются с 1, а не с 0 (кроме случаев
ksh
эмуляции), что согласуется с массивом Борна (параметры позиции $ @, который zsh
также представлен в виде массива $ argv) и csh
массивами.
- они являются отдельным типом от нормальных / скалярных переменных. Операторы относятся к ним по-разному и, как вы обычно ожидаете.
$a
это не то же самое, ${a[0]}
но расширяется до непустых элементов массива ( "${a[@]}"
для всех элементов, как в ksh
).
- это обычные массивы, а не редкие массивы.
a[5]=1
работает, но присваивает всем элементам от 1 до 4 пустую строку, если они не были назначены. Итак ${#a[@]}
(то же, ${#a}
что в ksh - это размер элемента индекса 0) - это число элементов в массиве и самый большой назначенный индекс.
- ассоциативные массивы поддерживаются.
- поддерживается большое количество операторов для работы с массивами, слишком большой, чтобы перечислять их здесь.
- массивы определены как
a=(x y)
. set -A a x y
также работает, но set -A a -- x y
не поддерживается, за исключением эмуляции ksh ( --
в эмуляции zsh не требуется).
ksh93
, (здесь описаны последние версии). ksh93
долгое время считавшийся экспериментальным, теперь можно найти во все большем количестве систем теперь, когда он выпущен как FOSS. Например, это /bin/sh
(где он заменил оболочку Bourne, оболочка /usr/xpg4/bin/sh
POSIX по-прежнему основана ksh88
) и ksh
of Solaris 11
. Его массивы расширяют и улучшают ksh88.
a=(x y)
может использоваться для определения массива, но так a=(...)
как также используется для определения составных переменных ( a=(foo=bar bar=baz)
), a=()
является неоднозначным и объявляет составную переменную, а не массив.
- массивы являются многомерными (
a=((0 1) (0 2))
), а элементы массива также могут быть составными переменными ( a=((a b) (c=d d=f)); echo "${a[1].c}"
).
a=([2]=foo [5]=bar)
Синтаксис может быть использован для определения разреженных массивов сразу.
- Размер ограничения снят.
- Не в меру
zsh
, но поддерживается большое количество операторов для манипулирования массивами.
"${!a[@]}"
чтобы получить список индексов массива.
- Ассоциативные массивы также поддерживаются как отдельный тип.
bash
, bash
это оболочка проекта GNU. Он используется как sh
в последних версиях OS / X и некоторых дистрибутивах GNU / Linux. bash
массивы в основном эмулируют ksh88
с некоторыми особенностями ksh93
и zsh
.
a=(x y)
поддерживается. set -A a x y
не поддерживается a=()
создает пустой массив (без составных переменных в bash
).
"${!a[@]}"
для списка показателей.
a=([foo]=bar)
поддерживается синтаксис, а также несколько других из ksh93
и zsh
.
- последние
bash
версии также поддерживают ассоциативные массивы как отдельный тип.
yash
, Это относительно недавняя, чистая, многобайтовая реализация POSIX sh. Не в широком использовании. Его массивы являются еще одним чистым API, похожим наzsh
- массивы не редки
- Индексы массива начинаются с 1
- определяется (и объявляется) с
a=(var value)
- элементы вставлены, удалены или изменены с помощью
array
встроенного
array -s a 5 value
изменить 5- й элемент не удастся, если этот элемент не был назначен заранее.
- количество элементов в массиве
${a[#]}
, ${#a[@]}
является размером элементов в виде списка.
- массивы - это отдельный тип. Вам нужно
a=("$a")
переопределить скалярную переменную как массив, прежде чем вы сможете добавлять или изменять элементы.
- массивы не поддерживаются при вызове как
sh
.
Итак, из этого вы можете увидеть, что обнаружение для поддержки массива, что вы могли бы сделать с:
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
недостаточно, чтобы иметь возможность использовать эти массивы. Вам нужно определить команды-оболочки, чтобы назначить массивы как единое целое и отдельные элементы, и убедитесь, что вы не пытаетесь создавать разреженные массивы.
подобно
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
И вы получите доступ к элементам массива с "${a[$first_indice+n]}"
, весь список с "${a[@]}"
и использовать функции оболочки ( array_elements
, set_array
, set_array_element
) , чтобы получить количество элементов массива (в $REPLY
), установите массив в целом или назначения отдельных элементов.
Вероятно, не стоит усилий. Я хотел бы использовать perl
или ограничение массива оболочки Bourne / POSIX: "$@"
.
Если мы хотим, чтобы какой-то файл был получен из интерактивной оболочки пользователя для определения функций, которые используют массивы внутри, вот еще несколько замечаний, которые могут быть полезны.
Вы можете настроить zsh
массивы так, чтобы они больше походили на ksh
массивы в локальных областях (в функциях или анонимных функциях).
myfunction() {
[ -z "$ZSH_VERSION" ] || setopt localoption ksharrays
# use arrays of indice 0 in this function
}
Вы также можете эмулировать ksh
(улучшить совместимость ksh
для массивов и некоторых других областей) с:
myfunction() {
[ -z "$ZSH_VERSION" ] || emulate -L ksh
# ksh code more likely to work here
}
Имея это в виду , и вы готовы отказаться от поддержки yash
и ksh88
и более старые версии pdksh
производных, и до тех пор , пока вы не пытаются создать разреженные массивы, вы должны быть в состоянии последовательно использовать:
a[0]=foo
a=(foo bar)
(но не a=()
)
"${a[#]}"
, "${a[@]}"
,"${a[0]}"
в тех функциях, которые имеют emulate -L ksh
, в то время как zsh
пользователь все еще использует свои массивы, как правило, zsh.