Bash 매뉴얼 페이지에서는 ${!a}
이름이 지정된 변수의 내용을 반환하는 방법(간접 수준)을 설명합니다.a
이것을 사용하여 배열의 모든 요소를 반환하는 방법을 알고 싶습니다.
a=(one two three)
echo ${a[*]}
반품
one two three
나는 원해요:
b=a
echo ${!b[*]}
같은 것을 반환합니다. 불행하게도 그렇지 않고 대신 반환됩니다 0
.
고쳐 쓰다
답변을 듣고 보니 제 예가 다음과 같이 너무 단순하다는 것을 깨달았습니다.
b=("${a[@]}")
내가 필요하다고 말하는 모든 것을 성취할 것이다.
그럼 이게 내 상황이구나노력하다할 것:
LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)
whichone=$1 # 'lys' or 'diaspar'
_LIST=LIST_$whichone
LIST=${!_LIST[*]}
물론, Bash 매뉴얼 페이지를 자세히 살펴보면 마지막 줄이 단지 "배열"의 인덱스 $_LIST
(전혀 배열이 아님)를 반환하기 때문에 이것이 예상대로 작동하지 않는다는 것을 알 수 있습니다.
어쨌든 다음은 (지시한 대로) 작업을 수행해야 합니다.
LIST=($(eval echo \${$_LIST[*]}))
아니면... (내가 선택한 경로):
LIST_lys="lys1 lys2"
...
LIST=(${!_LIST})
물론 이는 요소에 공백이 포함되어 있지 않다고 가정합니다.
답변1
나는 bash 변수에 대한 간접 참조의 사용을 문자 그대로 받아들여야 한다고 생각합니다.
예를 들어. 원래 예의 경우:
a=(one two three)
echo ${a[*]} # one two three
b=a
echo ${!b[*]} # this would not work, because this notation
# gives the indices of the variable b which
# is a string in this case and could be thought
# as a array that conatins only one element, so
# we get 0 which means the first element
c='a[*]'
echo ${!c} # this will do exactly what you want in the first
# place
마지막 실제 시나리오에서는 아래 코드가 작업을 수행할 것이라고 믿습니다.
LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)
whichone=$1 # 'lys' or 'diaspar'
_LIST="LIST_$whichone"[*]
LIST=( "${!_LIST}" ) # Of course for indexed array only
# and not a sparse one
"${var[@]}"
혼란 $IFS
과 논증 확장을 피하는 표기법을 사용하는 것이 좋습니다 . 이것이 최종 코드입니다.
LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)
whichone=$1 # 'lys' or 'diaspar'
_LIST="LIST_$whichone"[@]
LIST=( "${!_LIST}" ) # Of course for indexed array only
# and not a sparse one
# It is essential to have ${!_LIST} quoted
답변2
요소를 명시적으로 복사해야 합니다. 인덱스 배열의 경우:
b=("${a[@]}")
연관 배열의 경우( a
값이 배열 변수의 이름인 변수가 아니라 배열 변수의 이름에 유의하십시오):
typeset -A b
for k in "${!a[@]}"; do b[$k]=${a[$k]}; done
배열에 변수 이름이 있는 경우 추가 단계를 통해 요소별 방법을 사용하여 키를 검색할 수 있습니다.
eval "keys=(\"\${!$name[@]}\")"
for k in "${keys[@]}"; do eval "b[\$k]=\${$name[\$k]}"; done
(경고: 이 기사의 코드는 브라우저에 직접 입력되었으며 테스트되지 않았습니다.)
답변3
${!b[*]}
array 에 사용된 인덱스로 확장됩니다 b
.
원하는 작업은 두 단계로 수행되어야 하므로 다음이 eval
도움이 될 것입니다 eval echo \${$b[*]}
. ( \
첫 $
번째 단계인 변수 확장을 통과하고 두 번째 단계에서만 확장을 통과하도록 보장합니다 eval
.)
매개변수 확장에 따라 두 가지 모두 간접 확장( ), 접두사가 붙은 이름( ) 및 배열 키 목록( )과 일치하는 데 !
사용됩니다 . 배열 키 목록은 예상되는 간접 확장 + 배열 요소 확장과 동일한 구문을 가지므로 후자는 지원되지 않습니다.{!a}
${!a*}
${!a[*]}
답변4
배열에 간접적으로 접근하려면 [@]
간접변수에 추가하면 됩니다 b=a[@]
.
이 변수가 설정된 경우:
a=(one two three)
printf '<%s> ' "${a[@]}"; echo
그러면 다음과 같이 작동합니다.
b="a[@]"
printf '<%s> ' "${!b}"
또는 간단하게:
echo "${!b}"
이러한 배열은 다음과 같이 복사할 수 있습니다.
newArr=( "${!b}" )
그런 다음 인쇄하십시오.
declare -p newArr
스크립트에서:
#!/bin/bash
a=(one two three)
echo "original array"
printf '<%s> ' "${a[@]}"; echo
echo "Indirect array with variable b=a[@]"
b="a[@]"
printf '<%s> ' "${!b}"; echo
echo "New array copied in newArr, printed with declare"
newArr=( "${!b}" )
declare -p newArr
물론 위의 모든 작업은 비희소 배열을 복사합니다. 모든 인덱스에는 값이 있습니다.
희소 배열
희소 배열은 정의되지 않은 요소를 포함할 수 있는 배열입니다.
예를 들어 a[8]=1234
요소를 정의했는데 bash에는 0~7이 존재하지 않습니다.
이러한 희소 배열을 복사하려면 이 방법을 사용하십시오.
이전 배열을 인쇄합니다.
$ oldarr[8]=1234 $ declare -p oldarr declare -a oldarr=([8]="1234")
배열 이름을 바꾸고 문자열을 캡처합니다.
$ str=$(declare -p oldarr | sed 's/oldarr=/newarr=/')
이렇게 생성된 문자열을 평가하여 새 배열이 정의되었습니다.
$ eval "$str" $ declare -p newarr declare -a newarr=([8]="1234")