Как передать массив как аргумент функции?

При борьбе некоторое время передачи массива как аргумент, но это не работает так или иначе. Я попробовал как ниже:

#! /bin/bash

function copyFiles{
   arr="$1"
   for i in "${arr[@]}";
      do
          echo "$i"
      done

}

array=("one" "two" "three")

copyFiles $array

Ответ с объяснением был бы хорош.

Править: В основном я в конечном счете вызову функцию из другого файла сценария. Объясните ограничения, если это возможно.

62
задан 15 September 2015 в 01:50

9 ответов

  • Расширение массива без индекса только дает первый элемент, использовать

    copyFiles "${array[@]}"
    

    вместо

    copyFiles $array
    
  • Используйте хижину

    #!/bin/bash
    
  • Используйте корректный синтаксис функций

    Допустимые варианты

    function copyFiles {…}
    function copyFiles(){…}
    function copyFiles() {…}
    

    вместо

    function copyFiles{…}
    
  • Используйте правильный синтаксис для получения параметра массива

    arr=("$@")
    

    вместо

    arr="$1"
    

Поэтому

#!/bin/bash
function copyFiles() {
   arr=("$@")
   for i in "${arr[@]}";
      do
          echo "$i"
      done

}

array=("one" "two" "three")

copyFiles "${array[@]}"

Вывод (мой сценарий имеет имя foo)

$ ./foo   
one
two
three
90
ответ дан 22 November 2019 в 23:37

Вы могли также передать массив как ссылку. т.е.:

#!/bin/bash

function copyFiles {
   local -n arr=$1

   for i in "${arr[@]}"
   do
      echo "$i"
   done
}

array=("one" "two" "three")

copyFiles array

, но примечание, которое любые модификации к прибытию будут сделаны выстроить.

20
ответ дан 22 November 2019 в 23:37

Существует несколько проблем. Вот рабочая форма:

#!/bin/bash
function copyFiles {
   arr=( "$@" )
   for i in "${arr[@]}";
      do
          echo "$i"
      done

}

array=("one" "two" "three")
copyFiles "${array[@]}"
  • должно быть, по крайней мере, пространство между объявлением функции, и {

  • Вы не можете использовать $array, поскольку array массив не переменная. Если Вы хотите получить все значения использования массива "${array[@]}"

  • В Вас основное объявление функции, Вам нужно arr="$@", когда "${array[@]}" расширится до индексируемых значений, разделенных пробелами, если Вы будете использовать $1, Вы получили бы только первое значение. Получить все использование значений arr="$arr[@]}".

8
ответ дан 22 November 2019 в 23:37

Здесь следует немного большему примеру. Для объяснения см. комментарии в коде.

#!/bin/bash -u
# ==============================================================================
# Description
# -----------
# Show the content of an array by displaying each element separated by a
# vertical bar (|).
#
# Arg Description
# --- -----------
# 1   The array
# ==============================================================================
show_array()
{
    declare -a arr=("${@}")
    declare -i len=${#arr[@]}
    # Show passed array
    for ((n = 0; n < len; n++))
    do
        echo -en "|${arr[$n]}"
    done
    echo "|"
}

# ==============================================================================
# Description
# -----------
# This function takes two arrays as arguments together with their sizes and a
# name of an array which should be created and returned from this function.
#
# Arg Description
# --- -----------
# 1   Length of first array
# 2   First array
# 3   Length of second array
# 4   Second array
# 5   Name of returned array
# ==============================================================================
array_demo()
{
    declare -a argv=("${@}")                           # All arguments in one big array
    declare -i len_1=${argv[0]}                        # Length of first array passad
    declare -a arr_1=("${argv[@]:1:$len_1}")           # First array
    declare -i len_2=${argv[(len_1 + 1)]}              # Length of second array passad
    declare -a arr_2=("${argv[@]:(len_1 + 2):$len_2}") # Second array
    declare -i totlen=${#argv[@]}                      # Length of argv array (len_1+len_2+2)
    declare __ret_array_name=${argv[(totlen - 1)]}     # Name of array to be returned

    # Show passed arrays
    echo -en "Array 1: "; show_array "${arr_1[@]}"
    echo -en "Array 2: "; show_array "${arr_2[@]}"

    # Create array to be returned with given name (by concatenating passed arrays in opposite order)
    eval ${__ret_array_name}='("${arr_2[@]}" "${arr_1[@]}")'
}

########################
##### Demo program #####
########################
declare -a array_1=(Only 1 word @ the time)                                       # 6 elements
declare -a array_2=("Space separated words," sometimes using "string paretheses") # 4 elements
declare -a my_out # Will contain output from array_demo()

# A: Length of array_1
# B: First array, not necessary with string parentheses here
# C: Length of array_2
# D: Second array, necessary with string parentheses here
# E: Name of array that should be returned from function.
#          A              B             C              D               E
array_demo ${#array_1[@]} ${array_1[@]} ${#array_2[@]} "${array_2[@]}" my_out

# Show that array_demo really returned specified array in my_out:
echo -en "Returns: "; show_array "${my_out[@]}"
3
ответ дан 22 November 2019 в 23:37

Лучший способ состоит в том, чтобы передать как аргументы положения. Ничто иное. Можно передать как строка, но этот путь может доставить некоторые неприятности. Пример:

array=(one two three four five)

function show_passed_array(){
  echo $@
}

или

function show_passed_array(){
  while $# -gt 0;do
    echo $1;shift
  done
}

    show_passed_array ${array[@]}

вывод:

  one two three four five

Вы имеете в виду, имеет ли значение массива символы пробела, необходимо заключить элементы в кавычки сначала, прежде чем передача для доступа к значению индексом в функции будет использовать $1$ 2$ 3... параметры положения. Где индекс 0-> 1, 1-> 2... Выполнить итерации доступа лучше использовать всегда 1$ и после Сдвига. Ничто дополнительное не необходимо. Можно передать аргументы без любого массива как это:

show_passed_array one two three four five

медиа удара автоматически создают массив из передаваемых аргументов, которые передали их для функционирования, и затем у Вас есть аргументы положения. Кроме того, когда Вы пишете $ {массив [2]}, Вы действительно пишете последовательный аргумент один два три четыре и передали их функции. Таким образом, те вызовы эквивалентны.

1
ответ дан 22 November 2019 в 23:37

Если Вы хотите передать один или несколько аргументов И массив, я предлагаю это изменение в сценарии @A.B.
Массив должен быть последним аргументом, и только один массив может быть передан

#!/bin/bash
function copyFiles() {
   local msg="$1"   # Save first argument in a variable
   shift            # Shift all arguments to the left (original $1 gets lost)
   local arr=("$@") # Rebuild the array with rest of arguments
   for i in "${arr[@]}";
      do
          echo "$msg $i"
      done
}

array=("one" "two" "three")

copyFiles "Copying" "${array[@]}"

Вывод:

$ ./foo   
Copying one
Copying two
Copying three
21
ответ дан 22 November 2019 в 23:37

Столь же ужасный, как это, вот обходное решение, которое работает, пока Вы не передаете массив явно, но переменную, соответствующую массиву:

function passarray()
{
    eval array_internally=("$(echo '${'$1'[@]}')")
    # access array now via array_internally
    echo "${array_internally[@]}"
    #...
}

array=(0 1 2 3 4 5)
passarray array # echo's (0 1 2 3 4 5) as expected

Я уверен, что кто-то может придумать более чистую реализацию идеи, но я нашел, что это лучшее решение, чем передача массива как "{array[@]"} и затем получая доступ к нему внутренне использование array_inside=("$@"). Это становится сложным, когда существуют другие позиционные /getopts параметры. В этих случаях я должен был сначала определить и затем удалить параметры, не связанные с массивом с помощью некоторой комбинации shift и удаление элемента массива.

Пуристская перспектива, вероятно, просматривает этот подход как нарушение языка, но практично разговор, этот подход сохранил меня много горя. На связанную тему я также использую eval присваивать внутренне созданный массив переменной, названной согласно параметру target_varname Я передаю функции:

eval $target_varname=$"(${array_inside[@]})"
1
ответ дан 22 November 2019 в 23:37

Я предлагаю избежать каких-либо ограничений на «передачу аргументов массива (ов)» в функцию с помощью ... передавая строки, и сделайте их массивом ВНУТРИ функции:

#!/bin/bash

false_array1='1 2 3 4 5'
false_array2='my super fake array to deceive my function'
my_normal_string='John'

function i_love_arrays(){
  local myNumbers=("$1")
  local mySentence=("$2")
  local myName="$3"
  echo "My favorite numbers are, for sure: "
  for number in ${myNumbers[@]}
  do
    echo $number
  done
  echo "Let's make an ugly split of a sentence: "
  for word in ${mySentence[@]}
  do
    echo $word
  done
  echo "Yeah, I know, glad to meet you too. I'm ${myName}."
}

i_love_arrays "${false_array1}" "${false_array2}" "${my_normal_string}"
0
ответ дан 7 February 2020 в 09:27

Использование ссылок (самый простой способ; лучший и единственный способ передачи ассоциативных массивов):

print()
{
    [ "$1" = "arr" ] || { declare -n arr; arr="$1"; }
    # The name of reference mustn't match the input coming to the function.
    # If it does, use the name directly as array instead of reference.
    
    echo "${arr[@]}"
}

print arr

Для обычных (неассоциативных) массивов:

Вот функция, которая копирует переданный массив в новый (локальный) массив для дальнейшего использования. Для длинных массивов может потребоваться много времени.

copy_fn()
{
    eval local newarr=\(\${$1[@]}\)
    echo ${newarr[@]}
}

Далее, как и в C++, вы можете передавать только указатель массива, а в python — как общую переменную, которую вы также можете изменять.

Вот подход с общими переменными... полезен для длинных массивов.

modify_arr()
{
    eval local ptr=$1        # works as if ptr is a pointer to actual "array-name" (arr)  # the original array is, thus, still same, not a copy
    eval $ptr+=(1)           # modify the array
    echo ${ptr[@]}           # will print name of the array (arr)
    eval echo \$\{$ptr[@]\}  # will print the actual array (arr)
}

modify_arr a
echo ${a[@]}

-Himanshu

0
ответ дан 18 November 2020 в 16:45

Другие вопросы по тегам:

Похожие вопросы: