Как я могу передать массив в качестве параметра функции bash?
Примечание: не найдя ответа здесь о переполнении стека, я сам опубликовал свое несколько грубое решение. Он допускает передачу только одного массива и является последним элементом списка параметров. На самом деле, он вообще не передает массив, а список его элементов, которые повторно собираются в массив с помощью метода named_function (), но у меня это сработало. Если кто-то знает лучший способ, не стесняйтесь добавлять его здесь.
Ответы:
Вы можете передать несколько массивов в качестве аргументов, используя что-то вроде этого:
будет эхом
Редактировать / заметки: (из комментариев ниже)
descTable
иoptsTable
передаются как имена и раскрываются в функции. Таким образом, нет$
необходимости при указании в качестве параметров.descTable
определении etclocal
, поскольку локальные элементы видны для вызываемых ими функций.!
in${!1}
расширяет переменную arg 1.declare -a
просто делает индексированный массив явным, это не является строго необходимым.источник
Примечание. Это довольно грубое решение, которое я опубликовал сам, после того как не нашел ответа здесь о переполнении стека. Он допускает передачу только одного массива и является последним элементом списка параметров. На самом деле, он вообще не передает массив, а список его элементов, которые повторно собираются в массив с помощью метода named_function (), но у меня это сработало. Несколько позже Кен опубликовал свое решение, но я оставил свое здесь для «исторической» ссылки.
Улучшено TheBonsai, спасибо.
источник
called_function "${#array[@]}" "${array[@]}" "${#array2[@]}" "${array2[@]}"
и т.д. ... все еще с некоторыми очевидными ограничениями, но на самом деле лучше решить проблему так, как поддерживает язык, а не пытаться заставить язык работать так, как вы привыкли в других языках.Комментируя решение Кена Бертельсона и отвечая Яну Хеттиху:
Как это устроено
takes_ary_as_arg descTable[@] optsTable[@]
линия вtry_with_local_arys()
функции посылает:descTable
иoptsTable
массивы , которые доступны дляtakes_ary_as_arg
функции.takes_ary_as_arg()
Функция получаетdescTable[@]
и вoptsTable[@]
виде строк, что означает$1 == descTable[@]
и$2 == optsTable[@]
.в начале
takes_ary_as_arg()
функции используется${!parameter}
синтаксис, который называется косвенной ссылкой или иногда двойной ссылкой , это означает, что вместо использования$1
значения 's мы используем значение расширенного значения$1
, например:аналогично для
$2
.argAry1=("${!1}")
создаетargAry1
в виде массива (следующие в скобках=
) с развернутымdescTable[@]
, точно так же, как записьargAry1=("${descTable[@]}")
непосредственно.declare
там не требуется.NB. Стоит отметить, что при инициализации массива с помощью этой квадратной формы новый массив инициализируется в соответствии с разделителем
IFS
или внутренним полем, который по умолчанию представляет собой табуляцию , перевод строки и пробел . в этом случае, поскольку он использовал[@]
обозначения, каждый элемент рассматривается сам по себе, как если бы он был в кавычках (вопреки[*]
).Мое бронирование с этим
В
BASH
локальной области видимости это текущая функция и каждая дочерняя функция, вызываемая из нее, это означает, чтоtakes_ary_as_arg()
функция «видит» ихdescTable[@]
иoptsTable[@]
массивы, таким образом, она работает (см. Объяснение выше).В таком случае, почему бы не посмотреть непосредственно на эти переменные? Это так же, как писать там:
Смотрите выше объяснение, которое просто копирует
descTable[@]
значения массива в соответствии с текущимIFS
.В итоге
Я также хочу подчеркнуть комментарий Денниса Уильямсона выше: разреженные массивы (массивы без всех ключей определяют - с «дырами» в них) не будут работать должным образом - мы потеряем ключи и «сгущим» массив.
При этом я вижу значение для обобщения, поэтому функции могут получать массивы (или копии), не зная имен:
для реальных копий: мы можем использовать eval для ключей, например:
а затем цикл, используя их для создания копии. Примечание: здесь
!
не используется его предыдущая косвенная / двойная оценка, а скорее в контексте массива он возвращает индексы (ключи) массива.descTable
иoptsTable
строки (без[@]
), мы могли бы использовать сам массив (как в ссылке) сeval
. для универсальной функции, которая принимает массивы.источник
Array1
, затем сArray2
передачей имен массивов становится удобно.Основная проблема здесь заключается в том, что разработчик (-и) bash, спроектировавший / реализовавший массивы, действительно испортил собаку. Они решили, что
${array}
это всего лишь короткая рука${array[0]}
, что было плохой ошибкой. Особенно, если учесть, что${array[0]}
это не имеет смысла и вычисляет пустую строку, если тип массива является ассоциативным.Присвоение массива принимает форму, в
array=(value1 ... valueN)
которой значение имеет синтаксис[subscript]=string
, тем самым присваивая значение непосредственно определенному индексу в массиве. Это позволяет создавать два типа массивов: с числовым индексированием и с хэш-индексированием (называемые ассоциативными массивами на языке bash). Это также позволяет создавать разреженные числовые индексы.[subscript]=
Сокращение от части является сокращением для численно индексированного массива, начиная с порядкового индекса 0 и увеличивая с каждым новым значением в операторе присваивания.Поэтому
${array}
следует оценивать весь массив, индексы и все. Следует оценить обратное значение оператора присваивания. Любой третий год CS должен знать это. В этом случае этот код будет работать точно так, как вы ожидаете:Затем передача массивов по значению функциям и присвоение одного массива другому будет работать так, как диктует остальная часть синтаксиса оболочки. Но поскольку они не сделали этого правильно, оператор присваивания
=
не работает для массивов, и массивы нельзя передавать по значению в функции или в подоболочки или выводить вообще (echo ${array}
) без кода, который можно было бы просмотреть через все это.Итак, если бы все было сделано правильно, то следующий пример показал бы, как полезность массивов в bash может быть существенно лучше:
результирующий вывод должен быть:
Затем массивы могут использовать оператор присваивания и передаваться по значению функциям и даже другим сценариям оболочки. Легко сохраняется путем вывода в файл и легко загружается из файла в сценарий.
Увы, мы были подведены превосходной командой разработчиков bash.
Таким образом, для передачи массива в функцию, на самом деле есть только одна опция, а именно использование функции nameref:
приведет к следующему выводу:
Поскольку это происходит по ссылке, вы также можете назначить массив в функции. Да, указанный массив должен иметь глобальную область видимости, но это не должно быть слишком сложным, учитывая, что это сценарий оболочки. Для передачи ассоциативного или разреженного индексированного массива по значению в функцию требуется бросить все индексы и значения в список аргументов (не слишком полезный, если это большой массив) в виде одной строки:
а затем написать кучу кода внутри функции, чтобы собрать массив.
источник
local -n
лучше и актуальнее, чем принятый ответ. Это решение также будет работать для переменной любого типа. Пример, приведенный в этом ответе, можно сократить доlocal -n ARR=${1}
. Однако-n
опцияlocal
/declare
доступна только в Bash версии 4.3 и выше.funky ARR
), shell выдаст предупреждениеcircular name reference
, потому что в основном функция попытается это сделатьlocal -n ARR=ARR
. Хорошая дискуссия на эту тему.В ответе DevSolar есть один момент, которого я не понимаю (возможно, у него есть конкретная причина для этого, но я не могу придумать одно): он устанавливает массив из позиционных параметров поэлементно, итеративно.
Более простой подход был бы
источник
пример
источник
Простой способ передать несколько массивов в качестве параметра - использовать разделенную символами строку. Вы можете назвать свой скрипт так:
Затем вы можете извлечь его в свой код следующим образом:
Таким образом, вы можете фактически передать несколько массивов в качестве параметров, и это не должно быть последними параметрами.
источник
Этот работает даже с пробелами:
источник
С помощью нескольких трюков вы можете передать именованные параметры в функции вместе с массивами.
Метод, который я разработал, позволяет получить доступ к параметрам, переданным в функцию, например:
Другими словами, вы можете не только вызывать ваши параметры по их именам (что делает ядро более читабельным), вы также можете передавать массивы (и ссылки на переменные - хотя эта функция работает только в bash 4.3)! Кроме того, все отображаемые переменные находятся в локальной области, как и 1 доллар (и другие).
Код, который делает эту работу довольно легким и работает как в bash 3, так и в bash 4 (это единственные версии, с которыми я его тестировал). Если вас интересуют другие подобные хитрости, которые делают разработку с помощью Bash намного приятнее и проще, вы можете взглянуть на мою среду Bash Infinity Framework , для которой был разработан приведенный ниже код.
источник
Просто чтобы добавить к принятому ответу, поскольку я обнаружил, что он не работает хорошо, если содержимое массива примерно так:
В этом случае каждый член массива разделяется, поэтому массив, который видит функция, эквивалентен:
Чтобы заставить этот случай работать, я нашел способ передать имя переменной в функцию, а затем использовать eval:
Просто мои 2 ©
источник
Как бы ужасно это ни было, вот обходной путь, который работает до тех пор, пока вы не передаете массив явно, а переменную, соответствующую массиву:
Я уверен, что кто-то может придумать более ясную реализацию этой идеи, но я нашел, что это лучшее решение, чем передача массива
"{array[@]"}
и последующий доступ к нему с помощью внутреннегоarray_inside=("$@")
. Это становится сложным, когда есть другие позиционныеgetopts
параметры. В этих случаях мне пришлось сначала определить, а затем удалить параметры, не связанные с массивом, используя некоторую комбинациюshift
и удаление элементов массива.С точки зрения пуристов этот подход, скорее всего, рассматривается как нарушение языка, но, прагматично говоря, этот подход спас меня от многих неприятностей. В смежной теме я также использую,
eval
чтобы присвоить внутренне построенный массив переменной, названной согласно параметру, которыйtarget_varname
я передаю функции:eval $target_varname=$"(${array_inside[@]})"
Надеюсь, это кому-нибудь поможет.
источник
Требование : функция для поиска строки в массиве.
Это небольшое упрощение решения DevSolar в том смысле, что оно использует переданные аргументы, а не копирует их.
источник
Мой короткий ответ:
${test_array[*]}
и${test_array2[*]}
должны быть окружены "", иначе у вас ничего не получится.источник