Припускаючи , що ви хочете обмежитися Bourne-подібних оболонок (багато інших раковин люблять csh, tcsh, rc, esабо fishпідтримку масиви , але написання сценарію сумісні в той же час Bourne-подібні оболонок і тим складно і взагалі безглуздо , оскільки вони інтерпретатори абсолютно різні і несумісні мови), зауважте, що між реалізаціями існують значні відмінності.
Оболонки Борна, що підтримують масиви:
ksh88(це перший масив, що реалізує, ksh88 все ще зустрічається, як і kshв більшості традиційних комерційних об'єднань, де це також є основою для 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емуляції), що відповідає масиву Bourne (параметри позиції $ @, який 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 емуляції (the --zsh emulation не потрібен).
ksh93. (тут описуються останні версії). ksh93, що довго вважається експериментальним, тепер можна знайти все більше і більше систем тепер, коли він був випущений як FOSS. Наприклад, це /bin/sh(там , де він замінив Bourne оболонки, /usr/xpg4/bin/sh, то POSIX оболонки по - , як і раніше грунтується на ksh88) і kshз 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-шлях.