[arrays] bash에서 배열을 매개 변수로 전달

bash 함수에 배열을 매개 변수로 전달하려면 어떻게해야합니까?

참고 : 스택 오버플로에 대한 답변을 찾지 못한 후 다소 조잡한 솔루션을 직접 게시했습니다. 하나의 배열 만 전달할 수 있으며 매개 변수 목록의 마지막 요소입니다. 실제로, 그것은 배열을 전혀 전달하지 않고, 그 요소의 목록을, called_function ()에 의해 배열로 다시 어셈블하지만, 그것은 나를 위해 일했습니다. 누군가 더 나은 방법을 알고 있다면 여기에 자유롭게 추가하십시오.



답변

다음과 같이 여러 배열을 인수로 전달할 수 있습니다 .

takes_ary_as_arg()
{
    declare -a argAry1=("${!1}")
    echo "${argAry1[@]}"

    declare -a argAry2=("${!2}")
    echo "${argAry2[@]}"
}
try_with_local_arys()
{
    # array variables could have local scope
    local descTable=(
        "sli4-iread"
        "sli4-iwrite"
        "sli3-iread"
        "sli3-iwrite"
    )
    local optsTable=(
        "--msix  --iread"
        "--msix  --iwrite"
        "--msi   --iread"
        "--msi   --iwrite"
    )
    takes_ary_as_arg descTable[@] optsTable[@]
}
try_with_local_arys

에코 :

sli4-iread sli4-iwrite sli3-iread sli3-iwrite
--msix  --iread --msix  --iwrite --msi   --iread --msi   --iwrite

편집 / 노트 : (아래 주석에서)

  • descTableoptsTable이름으로 전달하고 함수에 확장됩니다. 따라서 $매개 변수로 제공 될 때 필요 하지 않습니다 .
  • 이것은 여전히 descTableetc로 정의 된 경우에도 작동합니다.local로케일이 호출하는 함수에 표시되므로, .
  • !에서이 ${!1}인자 저장 한 변수를 확장한다.
  • declare -a 인덱스 배열을 명시 적으로 만들면 꼭 필요한 것은 아닙니다.

답변

참고 : 이것은 스택 오버플로에 대한 답변을 찾지 못한 후에 내가 게시 한 다소 조잡한 솔루션입니다. 하나의 배열 만 전달할 수 있으며 매개 변수 목록의 마지막 요소입니다. 실제로, 그것은 배열을 전혀 전달하지 않고, 그 요소의 목록을, called_function ()에 의해 배열로 다시 어셈블하지만, 그것은 나를 위해 일했습니다. 나중에 Ken은 자신의 솔루션을 게시했지만 “역사적”참조를 위해 여기에 보관했습니다.

calling_function()
{
    variable="a"
    array=( "x", "y", "z" )
    called_function "${variable}" "${array[@]}"
}

called_function()
{
    local_variable="${1}"
    shift
    local_array=("${@}")
}

TheBonsai에 의해 향상되었습니다.


답변

Ken Bertelson 솔루션에 대해 논평하고 Jan Hettich에게 답변 :

작동 원리

함수 의 takes_ary_as_arg descTable[@] optsTable[@]라인은 try_with_local_arys()다음을 보냅니다.

  1. 이것은 실제로 에 액세스 할 수 있는 descTableoptsTable배열 의 복사본을 만듭니다 .takes_ary_as_arg 함수에 .
  2. takes_ary_as_arg()함수는 수신 descTable[@]optsTable[@]문자열한다는 뜻 $1 == descTable[@]하고$2 == optsTable[@] .
  3. takes_ary_as_arg()함수 의 시작 부분 에서는 간접 참조 또는 때로는 이중 참조${!parameter} 라고 하는 구문 을 사용 합니다. 이는 을 사용 하는 대신 확장의 값 을 사용 한다는 것을 의미합니다 . 예 :$1$1

    baba=booba
    variable=baba
    echo ${variable} # baba
    echo ${!variable} # booba

    마찬가지로 $2 .

  4. 이것을 넣으면 직접 쓰는 것처럼 확장 된 배열 (다음에 괄호 ) 이 argAry1=("${!1}")만들어집니다 . 이 필요하지 않습니다.argAry1=descTable[@]argAry1=("${descTable[@]}")declare

주의 : 이 상당이 브래킷 형태를 이용하여 해당 배열 초기화 언급이에 따른 새로운 배열이다 초기화 IFS하거나 내부 필드 구분 기본으로 인 , 개행공간 . 이 경우 [@]표기법 을 사용했기 때문에 각 요소는 마치 인용 된 것처럼 보입니다 (와 반대로 [*]).

그것으로 내 예약

에서 BASH지역 변수의 범위는 현재의 기능과 호출 모든 어린이 기능입니다,이 사실에 번역 takes_ary_as_arg()기능이 그 “인식” descTable[@]optsTable[@]배열, 따라서이 작동 (설명 위 참조).

이 경우 왜 변수 자체를 직접 보지 않겠습니까? 그것은 거기에 쓰는 것과 같습니다.

argAry1=("${descTable[@]}")

descTable[@]current에 따라 배열의 값을 복사하는 위의 설명을 참조하십시오 IFS.

요약해서 말하자면

이것은 본질적으로 평소와 같이 가치에 의한 것이 아닙니다.

또한 위의 Dennis Williamson의 의견을 강조하고 싶습니다. 희소 배열 (모든 키가 정의되지 않은 배열- “구멍”이있는 배열)은 예상대로 작동하지 않습니다. 우리는 키를 풀고 배열을 “축합”합니다.

즉, 일반화의 가치를 알 수 있으므로 함수는 이름을 몰라도 배열 (또는 사본)을 얻을 수 있습니다.

  • ~ “복사본”의 경우 :이 기술은 충분하며 인덱스 (키)가 없어 졌다는 사실 만 알고 있어야합니다.
  • 실제 사본의 경우 키에 eval을 사용할 수 있습니다. 예를 들면 다음과 같습니다.

    eval local keys=(\${!$1})

그런 다음 루프를 사용하여 사본을 만듭니다. 참고 : 여기 !에서는 이전 간접 / 이중 평가가 아니라 배열 컨텍스트에서 배열 인덱스 (키)를 반환합니다.

  • 물론 우리가 전달 descTable하고 optsTable문자열을 ()없이 [@]사용한다면 배열 자체를 (참조로) 사용할 수 있습니다 eval. 배열을 받아들이는 일반 함수

답변

여기서 기본적인 문제는 배열을 설계 / 구현 한 배쉬 개발자가 실제로 문제를 해결했다는 것입니다. 그들은을 ${array}위한 짧은 손 이라고 결정했습니다 ${array[0]}. 이것은 나쁜 실수입니다. 특히 당신이 그것을 고려할 때${array[0]} 배열 유형이 연관되어 있으면 의미가 없으며 빈 문자열로 평가됩니다.

배열 을 할당하면 value에 array=(value1 ... valueN)구문 이있는 형식이 사용되므로 배열 [subscript]=string의 특정 인덱스에 직접 값을 할당 할 수 있습니다. 이를 통해 숫자 인덱스와 해시 인덱스 (bash 괄호에서 연관 배열이라고 함)의 두 가지 유형의 배열이 가능합니다. 또한 희소하게 숫자 인덱스 된 배열을 만들 수 있습니다. 오프 떠나는 [subscript]=부분은 0의 서수 인덱스에서 시작하여 할당 문에서 각각 새 값으로 증가하는 숫자 인덱스 배열 짧은 손입니다.

따라서 전체 배열, 인덱스 및 모두로 ${array}평가해야 합니다. 대입 문의 역으로 ​​평가해야합니다. 3 학년 CS 전공은이를 알아야합니다. 이 경우이 코드는 예상 한대로 작동합니다.

declare -A foo bar
foo=${bar}

그런 다음 값으로 배열을 함수에 전달하고 하나의 배열을 다른 배열에 지정하면 나머지 쉘 구문이 지시하는대로 작동합니다. 그러나이 작업을 제대로 수행하지 않았기 때문에 할당 연산자 =는 배열에서 작동하지 않으며 값을 통해 함수 또는 하위 셸 또는 일반적으로 ( echo ${array}) 출력으로 배열을 전달할 수 없습니다 .

따라서 올바르게 수행 된 경우 다음 예제는 bash에서 배열의 유용성이 실질적으로 더 나은 방법을 보여줍니다.

simple=(first=one second=2 third=3)
echo ${simple}

결과 출력은 다음과 같아야합니다.

(first=one second=2 third=3)

그런 다음 배열은 대입 연산자를 사용하고 값을 통해 함수 및 다른 셸 스크립트에 전달할 수 있습니다. 파일로 출력하여 쉽게 저장하고 파일에서 스크립트로 쉽게로드 할 수 있습니다.

declare -A foo
read foo <file

아아, 우리는 다른 최상급 배쉬 개발 팀에 의해 실망했습니다.

따라서 배열을 함수에 전달하려면 실제로 하나의 옵션 만 있으며 nameref 기능을 사용하는 것입니다.

function funky() {
    local -n ARR

    ARR=$1
    echo "indexes: ${!ARR[@]}"
    echo "values: ${ARR[@]}"
}

declare -A HASH

HASH=([foo]=bar [zoom]=fast)
funky HASH # notice that I'm just passing the word 'HASH' to the function

결과는 다음과 같습니다.

indexes: foo zoom
values: bar fast

이것은 참조로 전달되므로 함수의 배열에 할당 할 수도 있습니다. 예, 참조되는 배열은 전역 범위를 가져야하지만 이것이 쉘 스크립팅이라는 점을 고려할 때 너무 큰해서는 안됩니다. 연관 또는 희소 색인 배열을 값으로 함수에 전달하려면 모든 색인과 값을 인수 목록 (큰 배열 인 경우 너무 유용하지 않음)에 다음과 같은 단일 문자열로 던져야합니다.

funky "${!array[*]}" "${array[*]}"

그런 다음 함수 내부에 많은 코드를 작성하여 배열을 다시 어셈블합니다.


답변

DevSolar의 대답에는 이해할 수없는 한 가지 점이 있습니다 (아마도 특별한 이유가 있지만 생각할 수는 없습니다) : 그는 위치 매개 변수에서 요소별로 배열을 반복적으로 설정합니다.

더 쉬운 approuch는

called_function()
{
  ...
  # do everything like shown by DevSolar
  ...

  # now get a copy of the positional parameters
  local_array=("$@")
  ...
}


답변

function aecho {
  set "$1[$2]"
  echo "${!1}"
}

$ foo=(dog cat bird)

$ aecho foo 1
cat


답변

여러 배열을 매개 변수로 전달하는 쉬운 방법은 문자로 구분 된 문자열을 사용하는 것입니다. 다음과 같이 스크립트를 호출 할 수 있습니다.

./myScript.sh "value1;value2;value3" "somethingElse" "value4;value5" "anotherOne"

그런 다음 코드에서 다음과 같이 추출 할 수 있습니다.

myArray=$1
IFS=';' read -a myArray <<< "$myArray"

myOtherArray=$3
IFS=';' read -a myOtherArray <<< "$myOtherArray"

이 방법으로 실제로 여러 배열을 매개 변수로 전달할 수 있으며 마지막 매개 변수 일 필요는 없습니다.