Припускаючи , що ви хочете обмежитися 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-шлях.