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


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.