함수 인수로 배열을 전달하는 방법은 무엇입니까?


57

배열을 인수로 전달하는 동안 어려움을 겪고 있지만 어쨌든 작동하지 않습니다. 나는 다음과 같이 시도했다.

#! /bin/bash

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

}

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

copyFiles $array

설명이있는 답변이 좋을 것입니다.

편집 : 기본적으로 결국 다른 스크립트 파일에서 함수를 호출합니다. Plz는 가능한 경우 제약 조건을 설명합니다.

답변:


84
  • 인덱스없이 배열을 확장하면 첫 번째 요소 만 제공됩니다.

    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

고맙지 만 copyFiles {…} 함수가 올바른 구문이 아닙니까? 나는 새로운 bie이지만 구문으로 일부 프로그램을 성공적으로 실행합니다.
Ahsanul Haque

유효한 변종은 copyFiles {…}copyFiles(){…}하고 copyFiles() {…}있지만 copyFiles{…}. 변형이없는 공간에 주목하십시오()
AB

19

하나 이상의 인수와 배열을 전달하려면 @AB
Array 의 스크립트에 대한이 변경 사항이 마지막 인수 여야하며 하나의 배열 전달할 수 있습니다.

#!/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

2
배열이 마지막에 있어야하고 하나만 보내야한다는 것에 대해 +1
David '대머리 생강'

1
사용 주셔서 감사 shift합니다.
Itachi

때로는 shift의 인수를 사용하는 것이 유용하므로 배열 앞에 6 개의 인수가 있으면을 사용할 수 있습니다 shift 6.
스핀 업

"나머지 인수"를로 변환 arr합니다. 중간에 배열 매개 변수를 가질 수 있습니까? 아니면 여러 배열 매개 변수? function copyAndMove() { msg1=$1 ; arr1=...?... ; msg2=? ; arr2=...?... ; msg3=? ; ... }. 파이썬에서 정의하는 것처럼 : def copyAndMove(msg1="foo", cpFiles=[], msg2="bar", mvFiles=[], msg3="baz"): .... 신경 쓰지 마라. stackoverflow.com/a/4017175/472245
towi

18

배열을 참조로 전달할 수도 있습니다. 즉 :

#!/bin/bash

function copyFiles {
   local -n arr=$1

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

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

copyFiles array

그러나 arr을 수정하면 배열이 변경됩니다.


1
비록 정확히 내가 원하는 것은 아니지만 여전히 bash에서 참조로 전달하는 방법을 아는 것이 좋습니다. +1 :)
Ahsanul Haque

3
bash 4.3 이상 필요
dtmland

8

몇 가지 문제가 있습니다. 작업 양식은 다음과 같습니다.

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


필요arr=("$@")
AB

차이점을 보려면 break아래를 추가하십시오 echo "$i". 버전에서는 여전히 모든 요소를 ​​볼 수 있습니다. 그러나 세 줄이어야합니다.
AB

@heemayl : 작은 오타-{두 번째 글 머리 기호 배열에서 { "이 누락되었습니다 ..."$ {array [@]} "...
Cbhihe

3

다음은 약간 더 큰 예입니다. 설명은 코드의 주석을 참조하십시오.

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

1

가장 좋은 방법은 위치 인수로 전달하는 것입니다. 다른 건 없어 문자열로 전달할 수 있지만이 방법으로 문제가 발생할 수 있습니다. 예:

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, ... 액세스를 반복하려면 Shift 후 항상 $ 1을 사용하는 것이 가장 좋습니다. 추가가 필요하지 않습니다. 다음과 같은 배열없이 인수를 전달할 수 있습니다.

show_passed_array one two three four five

bash 미디어는 전달 된 인수에서 배열을 자동으로 작성하여 함수에 전달 한 다음 위치 인수를 갖습니다. 또한 $ {array [2]}를 쓸 때 실제로 결과 인수 1 2 3 4를 작성하여 함수에 전달했습니다. 따라서 해당 통화는 동일합니다.


1

추악한 것처럼 배열을 명시 적으로 전달하지 않고 배열에 해당하는 변수를 사용하는 한 작동하는 해결 방법이 있습니다.

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[@]})"

그것은 추악하고 불필요합니다. 이름으로 배열을 전달하려면 array_internally별명을 만드 십시오 declare -n array_internally=$1.. 그리고 "복잡하게 됨"과 "결정 후 제거 ..."에 관한 나머지는 배열을 전달하는 방법에 관계없이 적용되므로 그 점이 무엇인지 알 수 없습니다. 그리고 eval잠재적으로 특수 문자를 포함하는 배열을 ing하는 것은 나중에 슬픔이 일어나기를 기다리고 있습니다.
muru
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.