Проверка поддержки массива оболочкой

Есть ли сжатый способ тестирования поддержки массива локальной 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, например .)

Я ищу простой тест, который может быть без присмотра и включен в раздел Usage в начале скрипта или даже до его вызова.

  • Любой способ, с помощью которого я могу преобразовать любую заданную временную метку в стандартную в BASH
  • Пользовательский скрипт Bash
  • Как добраться домой, учитывая ПОЛЬЗОВАТЕЛЬ?
  • Как найти максимальный и минимальный размер файла вместе со своим путем в каталоге
  • Как сортировать строку, которая в сочетании с строкой + число с использованием сценария bash?
  • Сценарий оболочки Loop, если входной файл имеет больше входных данных
  • Какая цель переназначает переменную себе через эхо?
  • Bash: Родной способ избавиться от цитаты вокруг каждого элемента массива
  • 2 Solutions collect form web for “Проверка поддержки массива оболочкой”

    Предполагая, что вы хотите ограничить Bourne-подобные оболочки (многие другие оболочки, такие как csh , tcsh , rc , es или массивы поддержки fish но одновременно записывают сценарий, совместимый с Bourne-подобными оболочками, и это сложно и обычно бессмысленно, поскольку они интерпретаторы для совершенно разных и несовместимых языков), обратите внимание, что существуют существенные различия между реализациями.

    Оболочки Bourne, которые поддерживают массивы:

    • ksh88 (это первый, реализующий массивы, ksh88 по-прежнему найден как ksh в большинстве традиционных коммерческих Unices, где он также является основой для 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 openource до освобождения источника ksh93):

      В основном, как ksh88 но обратите внимание:

      • Некоторые старые реализации не поддерживали set -A array -- foo bar , (там не было необходимости).
      • ${#a[@]} является одним плюс индексом наибольшего назначенного индекса. ( a[1000]=1; echo "${#a[@]}" выводит 1001, хотя массив имеет только один элемент.
      • в новых версиях размер массива больше не ограничен (кроме размера целых чисел).
      • В последних версиях mksh есть несколько дополнительных операторов, основанных на bash , ksh93 или zsh таких как присвоения a la a=(xy) , 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=(xy) . set -A axy также работает, но set -A a -- xy не поддерживается, если только в эмуляции ksh (в эмуляции zsh не требуется).
    • ksh93 . (здесь описываются последние версии). ksh93 , давно рассмотренный экспериментальный, теперь можно найти во все большем количестве систем теперь, когда он был выпущен как FOSS. Например, это /bin/sh (где он заменил оболочку Bourne, /usr/xpg4/bin/sh , оболочка POSIX по-прежнему основана на ksh88 ) и ksh Solaris 11 . Его массивы расширяются и усиливают ksh88.

      • a=(xy) может использоваться для определения массива, но поскольку a=(...) также используется для определения составных переменных ( a=(foo=bar bar=baz) ), a=() неоднозначно и объявляет составная переменная, а не массив.
      • массивы многомерны ( a=((0 1) (0 2)) ), а элементы массива также могут быть составными переменными ( a=((ab) (c=dd=f)); echo "${a[1].c}" ).
      • A a=([2]=foo [5]=bar) синтаксис может использоваться для определения разреженных массивов одновременно.
      • Ограничения по размеру отменены.
      • Не в пределах zsh , но большое количество поддерживаемых операторов, а также для управления массивами.
      • "${!a[@]}" чтобы получить список индексов массива.
      • ассоциативные массивы также поддерживаются как отдельный тип.
    • bash . bash – оболочка проекта GNU. Он используется как sh в последних версиях OS / X и некоторых дистрибутивов GNU / Linux. bash основном эмулируют ksh88 с некоторыми особенностями ksh93 и zsh .

      • a=(xy) . set -A axy не поддерживается. a=() создает пустой массив (нет составных переменных в bash ).
      • "${!a[@]}" для списка индексов.
      • Поддерживается синтаксис a=([foo]=bar) а также несколько других из ksh93 и zsh .
      • последние версии bash также поддерживают ассоциативные массивы как отдельный тип.
    • yash . Это сравнительно недавняя, чистая, многобайтовая реализация POSIX sh. Не в широком использовании. Его массивы – еще один чистый API, похожий на zsh

      • массивы не редки
      • определяется (и объявляется) с помощью a=(var value)
      • элементы вставлены, удалены или изменены с помощью встроенного array
      • array -sa 5 value для изменения 5- го элемента завершится неудачно, если этот элемент не был назначен заранее.
      • число элементов в массиве равно ${a[#]} , ${#a[@]} являющемуся размером элементов в виде списка.
      • массивы – это отдельный тип. Вам нужно a=("$a") переопределить скалярную переменную в виде массива, прежде чем вы сможете добавлять или изменять элементы.
      • массивы не поддерживаются при вызове sh .

    Таким образом, вы можете видеть, что обнаружение поддержки массива, с которой вы могли бы справиться:

     if (unset a; set -A aa; eval "a=(ab)"; 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 -- ab 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 -sa 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[$first_indice+n]}" , весь список с "${a[@]}" и используйте функции-обертки ( array_elements , set_array , set_array_element ), чтобы получить количество элементы массива (в $REPLY ), установите массив в целом или назначьте отдельные элементы.

    Наверное, не стоит усилий. Я бы использовал perl или limit для массива оболочки 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 } 

    Имея это в виду, и вы готовы отказаться от поддержки ksh88 и ksh88 и более старых версий производных pdksh , и пока вы не пытаетесь создать разреженные массивы, вы должны иметь возможность последовательно использовать:

    • a[0]=foo
    • a=(foo bar) (но не a=() )
    • ${a[#]} , "${a[@]}" , "${a[0]}"

    в тех функциях, которые имеют emulate -L ksh , в то время как пользователь zsh все еще использует свои / ее массивы, как правило, zsh.

    Вы можете использовать eval чтобы попробовать синтаксис массива:

     is_array_support() ( eval 'a=(1)' ) >/dev/null 2>&1 if is_array_support; then echo support else echo not fi 
    Linux и Unix - лучшая ОС в мире.