Como passar um array como argumento de função?

37

Lutando por um tempo passando uma matriz como argumento, mas não está funcionando de qualquer maneira. Eu tentei como abaixo:

#! /bin/bash

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

}

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

copyFiles $array

Uma resposta com explicação seria legal.

Edit: Basicamente, eu irei eventualmente chamar a função de outro arquivo de script. Plz explica as restrições, se possível.

    
por Ahsanul Haque 15.09.2015 / 10:50

7 respostas

64
  • Expandir uma matriz sem um índice apenas fornece o primeiro elemento, use

    copyFiles "${array[@]}"
    

    em vez de

    copyFiles $array
    
  • Use uma she-bang

    #!/bin/bash
    
  • Use a sintaxe correta da função

    Variantes válidas são

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

    em vez de

    function copyFiles{…}
    
  • Use a sintaxe certa para obter o parâmetro da matriz

    arr=("$@")
    

    em vez de

    arr="$1"
    

Portanto

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

}

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

copyFiles "${array[@]}"

A saída é (meu script tem o nome foo )

$ ./foo   
one
two
three
    
por A.B. 15.09.2015 / 11:24
14

Você também pode passar o array como referência. ou seja:

#!/bin/bash

function copyFiles {
   local -n arr=$1

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

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

copyFiles array

mas note que qualquer modificação na arr será feita para o array.

    
por user448115 15.09.2015 / 12:15
12

Se você quiser passar um ou mais argumentos E uma matriz, proponho essa alteração para o script de @ A.B.
Matriz deve ser o argumento último e apenas uma matriz pode ser passada

#!/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[@]}"

Saída:

$ ./foo   
Copying one
Copying two
Copying three
    
por SBF 12.01.2018 / 11:26
7

Existem alguns problemas. Aqui está o formulário de trabalho:

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

}

array=("one" "two" "three")
copyFiles "${array[@]}"
  • É preciso haver pelo menos um espaço entre a declaração de função e {

  • Você não pode usar $array , pois array é uma matriz, não uma variável. Se você deseja obter todos os valores de uma matriz, use "${array[@]}"

  • Na sua declaração de função principal, você precisa de arr="$@" as "${array[@]}" expandirá para os valores indexados separados por espaços, se você usar $1 , obterá apenas o primeiro valor. Para obter todos os valores, use arr="$arr[@]}" .

por heemayl 15.09.2015 / 11:36
2

Aqui segue um exemplo um pouco maior. Para explicação, veja os comentários no código.

#!/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[@]}"
    
por Ulf Oreborn 11.10.2016 / 12:34
0

A melhor maneira é passar como argumentos de posição. Nada mais. Você pode passar como string, mas desta forma pode causar alguns problemas. Exemplo:

array=(one two three four five)

function show_passed_array(){
  echo $@
}

ou

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

    show_passed_array ${array[@]}

saída:

  one two three four five

Você quer dizer que se o valor da matriz tiver símbolos de espaço, você deve citar os elementos antes de passar para acessar o valor pelo índice na função. Use os parâmetros de posição $ 1 $ 2 $ 3 .... Onde índice 0 - > 1, 1 - > 2, ... Para iterar o acesso, é melhor usar sempre $ 1 e depois de Shift. Nada adicional é necessário. Você pode passar argumentos sem uma matriz como esta:

show_passed_array one two three four five

O bash media constrói automaticamente uma matriz a partir dos argumentos passados que os transmitiram para a função e, em seguida, você tem argumentos de posição. Além disso, quando você escreve $ {array [2]} você realmente escreve um argumento consequente um dois três quatro e os passa para a função. Então essas chamadas são equivalentes.

    
por Anatoly 25.08.2017 / 12:30
0

Por mais feia que seja, aqui está uma solução alternativa que funciona contanto que você não esteja transmitindo uma matriz explicitamente, mas uma variável correspondente a uma matriz:

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

Tenho certeza de que alguém pode apresentar uma implementação mais limpa da ideia, mas descobri que essa é uma solução melhor do que transmitir uma matriz como "{array[@]"} e acessá-la internamente usando array_inside=("$@") . Isso se torna complicado quando há outros parâmetros posicionais / getopts . Nesses casos, eu tive que primeiro determinar e depois remover os parâmetros não associados à matriz usando alguma combinação de shift e remoção do elemento da matriz.

Uma perspectiva purista provavelmente vê essa abordagem como uma violação da linguagem, mas, pragmaticamente falando, essa abordagem me salvou um monte de tristeza. Em um tópico relacionado, também uso eval para atribuir uma matriz construída internamente a uma variável nomeada de acordo com um parâmetro target_varname I passar para a função:

eval $target_varname=$"(${array_inside[@]})"
    
por Blake Schultze 12.07.2018 / 00:02

Tags