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
편집 / 노트 : (아래 주석에서)
descTable
및optsTable
이름으로 전달하고 함수에 확장됩니다. 따라서$
매개 변수로 제공 될 때 필요 하지 않습니다 .- 이것은 여전히
descTable
etc로 정의 된 경우에도 작동합니다.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()
다음을 보냅니다.
- 이것은 실제로 에 액세스 할 수 있는
descTable
및optsTable
배열 의 복사본을 만듭니다 .takes_ary_as_arg
함수에 . takes_ary_as_arg()
함수는 수신descTable[@]
및optsTable[@]
문자열한다는 뜻$1 == descTable[@]
하고$2 == optsTable[@]
.-
takes_ary_as_arg()
함수 의 시작 부분 에서는 간접 참조 또는 때로는 이중 참조${!parameter}
라고 하는 구문 을 사용 합니다. 이는 값 을 사용 하는 대신 확장 값 의 값 을 사용 한다는 것을 의미합니다 . 예 :$1
$1
baba=booba variable=baba echo ${variable} # baba echo ${!variable} # booba
마찬가지로
$2
. - 이것을 넣으면 직접 쓰는 것처럼 확장 된 배열 (다음에 괄호 ) 이
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"
이 방법으로 실제로 여러 배열을 매개 변수로 전달할 수 있으며 마지막 매개 변수 일 필요는 없습니다.