Существует ли краткий способ проверки поддержки массивов локальной Bourne-подобной оболочкой в командной строке?
Это всегда возможно:
$ arr=(0 1 2 3);if [ "${arr[2]}" != 2 ];then echo "No array support";fi
или тестирование $SHELL
и версия оболочки:
$ eval $(echo "$SHELL --version") | grep version
и затем читая справочную страницу, предполагая, что у меня есть доступ к ней. (Даже там, писать с /bin/bash
, я предполагаю , что все Bourne-подобные оболочки допускают длинный вариант --version
, когда что перерывы для KSH , например .)
Я ищу простой тест, который можно было бы оставить без присмотра и включить в раздел « Использование » в начале сценария или даже перед его вызовом.
shell-script
shell
array
Cbhihe
источник
источник
csh
это не оболочка Борна.tcsh
тоже не один (этоcsh
исправлено с некоторыми ошибками)$SHELL
это предпочтительная оболочка пользователя, как$EDITOR
и его предпочтительный текстовый редактор. Это имеет мало общего с работающей в данный момент оболочкой.eval
Использование вывода в$SHELL --version
качестве шелл-кода не имеет смысла.Ответы:
Предполагая , что вы хотите ограничиться 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
может быть любое арифметическое выражение.${#a[@]}
номер назначенного элемента в массиве (не самый большой назначенный индекс).[[ -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
но со значительными различиями: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
ofSolaris 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
a=(var value)
array
встроенногоarray -s a 5 value
изменить 5- й элемент не удастся, если этот элемент не был назначен заранее.${a[#]}
,${#a[@]}
является размером элементов в виде списка.a=("$a")
переопределить скалярную переменную как массив, прежде чем вы сможете добавлять или изменять элементы.sh
.Итак, из этого вы можете увидеть, что обнаружение для поддержки массива, что вы могли бы сделать с:
недостаточно, чтобы иметь возможность использовать эти массивы. Вам нужно определить команды-оболочки, чтобы назначить массивы как единое целое и отдельные элементы, и убедитесь, что вы не пытаетесь создавать разреженные массивы.
подобно
И вы получите доступ к элементам массива с
"${a[$first_indice+n]}"
, весь список с"${a[@]}"
и использовать функции оболочки (array_elements
,set_array
,set_array_element
) , чтобы получить количество элементов массива (в$REPLY
), установите массив в целом или назначения отдельных элементов.Вероятно, не стоит усилий. Я хотел бы использовать
perl
или ограничение массива оболочки Bourne / POSIX:"$@"
.Если мы хотим, чтобы какой-то файл был получен из интерактивной оболочки пользователя для определения функций, которые используют массивы внутри, вот еще несколько замечаний, которые могут быть полезны.
Вы можете настроить
zsh
массивы так, чтобы они больше походили наksh
массивы в локальных областях (в функциях или анонимных функциях).Вы также можете эмулировать
ksh
(улучшить совместимостьksh
для массивов и некоторых других областей) с:Имея это в виду , и вы готовы отказаться от поддержки
yash
иksh88
и более старые версииpdksh
производных, и до тех пор , пока вы не пытаются создать разреженные массивы, вы должны быть в состоянии последовательно использовать:a[0]=foo
a=(foo bar)
(но неa=()
)"${a[#]}"
,"${a[@]}"
,"${a[0]}"
в тех функциях, которые имеют
emulate -L ksh
, в то время какzsh
пользователь все еще использует свои массивы, как правило, zsh.источник
Вы можете использовать,
eval
чтобы попробовать синтаксис массива:источник
ksh88
поддерживает массивы, но нетa=()
. Вksh93
,a=()
объявляет составную переменную, а не массив, если переменная не была объявлена как массив заранее.yash
, вы не делаете,a[5]=1
ноarray -s a 5 1
ksh93
меня удивила, не могли бы вы дать мне часть документации об этом. Я добавляю1
в массив, чтобы он работал.