희소 배열

희소 배열

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이 존재하지 않습니다.

이러한 희소 배열을 복사하려면 이 방법을 사용하십시오.

  1. 이전 배열을 인쇄합니다.

    $ oldarr[8]=1234
    $ declare -p oldarr
    declare -a oldarr=([8]="1234")
    
  2. 배열 이름을 바꾸고 문자열을 캡처합니다.

    $ str=$(declare -p oldarr | sed 's/oldarr=/newarr=/')
    
  3. 이렇게 생성된 문자열을 평가하여 새 배열이 정의되었습니다.

    $ eval "$str"
    $ declare -p newarr
    declare -a newarr=([8]="1234")
    

관련 정보