변수 배열 이름을 가진 bash 루프 연관 배열

변수 배열 이름을 가진 bash 루프 연관 배열

연관 배열이 많지만 루프를 1개만 사용하고 싶습니다. 주어진 이름으로 루프 배열 선택

변수를 사용하여 배열 이름의 일부를 선택/구축한 다음 해당 이름으로 반복하고 싶지만 작동하지 않습니다.

OUTPUT3 및 OUTPUT4와 유사하지만 구문이 잘못되었습니다.

출력 3의 경우 "bash error replacement"가 표시됩니다.

출력 4의 경우 "배열 이름만 있고 0"이 표시됩니다.

#!/bin/bash
clear

declare -A a1 a2 a3

a1['1']="1-1V"

a2['1']="2-1V"
a2['2']="2-2V"

a3['1']="3-1V"
a3['2']="3-2V"
a3['3']="3-3V"

# 1 OUTPUT WORKS
for i in ${!a1[*]}
do
echo -e "$i : ${a1[$i]}"
done

# 2 OUTPUT WORKS
for i in ${!a2[*]}
do
echo -e "$i : ${a2[$i]}"
done

# 3 OUTPUT - WRONG SYNTAX
selectkey="3"
for i in ${!a$selectkey[@]}
do
echo -e "$i : ${a$selectkey[$i]}"
done

# 4 OUTPUT - WRONG SYNTAX
key="3"
aselect="a${key}[*]"
# THIS ECHO WORKS
echo -e "ARRAY: ${!aselect}"

for i in ${!aselect[@]}
do
echo -e "$i : ${aselect[$i]}"
done

고쳐 쓰다

해결책은 nameref|declare -n

이것은 지금 나에게 효과적입니다.

#!/bin/bash
clear

declare -A a1 a2 a3

a1['1']="1-1V"

a2['1']="2-1V"
a2['2']="2-2V"

a3['1']="3-1V"
a3['2']="3-2V"
a3['3']="3-3V"

varname="a3"
counter=1

declare -n refname=${varname}

for i in "${!refname[@]}"
do
echo -e "$counter ${refname[$counter]}"
counter=$((counter+1))
done

답변1

"nameref" 사용: declare -n a=b변수를 a변수의 별칭으로 만듭니다 b.

# 3 OUTPUT - use a "nameref"
selectkey="3"
declare -n ary="a$selectkey"

for i in "${!ary[@]}"
do
    echo "$i : ${ary[$i]}"
done

산출

3 : 3-3V
2 : 3-2V
1 : 3-1V

연관 배열은 본질적으로 순서가 없습니다.

#4의 경우 에 설명된 대로 "간접 확장"을 사용하고 있습니다.쉘 매개변수 확장하지만 이 기술을 사용하여 배열의 인덱스를 가져올 수는 없습니다.

답변2

bash다차원 배열이 없습니다. 그러나 연관 배열과 키 연결( 결합된 문자열로 표시 key1) 을 사용하여 구현할 수 있습니다. 여기 몇 가지 예가 있어요.key2key1,key2

시작 시나리오를 고려하면

declare -A a

a[1,1]='1-1V'
a[2,1]='2-1V' a[2,2]='2-2V'
a[3,1]='3-1V' a[3,2]='3-2V' a[3,3]='3-3V'

모든 a[1,*]값:

for i in $(printf "%s\n" "${!a[@]}" | awk -F, -vk='1' '$1==k {print $2}')
do
    printf "%s: %s\n" "$i" "${a[1,$i]}"
done

산출

1: 1-1V

모든 a[*,2]값:

for i in $(printf "%s\n" "${!a[@]}" | awk -F, -vk='2' '$2==k {print $1}')
do
    printf "%s: %s\n" "$i" "${a[$i,2]}"
done

산출

3: 3-2V
2: 2-2V

키 세트를 생성하는 또 다른 방법:

for i in $(printf "%s\n" "${!a[@]}" | awk -F, -vk='1' '$2==k')
do
    printf "%s: %s\n" "$i" "${a[$i]}";
done

산출

1,1: 1-1V
3,1: 3-1V
2,1: 2-1V

모든 경우에 키는 숫자 순서대로 되어 있지 않습니다. 필요한 경우 printf | awk파이프를 전달하도록 구성을 수정할 수 있습니다 sort -n(숫자 키 가정).

awk필드 번호와 원하는 키 값을 지정하도록 구성을 일반화할 수도 있습니다 . 이는 아마도 함수에서 키 생성을 숨김으로써 캡슐화에 도움이 될 것입니다.

awk -F, -vfield=2 -vkey=1 '$field==key'

답변3

인덱스가 숫자인 경우 연관 배열보다는 일반 배열을 사용하는 것이 더 좋습니다. 둘 다 희박할 수 있지만 일반 배열을 사용하면 숫자 순서로 키를 반복할 수 있는 반면 연관 배열을 사용하면 본질적으로 무작위입니다. (다른 언어에서는 희소 배열을 얻으려면 연관 배열이 필요할 수도 있습니다.) 비교:

$ declare -A a=([11]=a [22]=b [33]=c ) 
$ echo "${a[@]}"
b a c
$ declare -a b=([11]=a [22]=b [33]=c)
$ echo "${b[@]}"
a b c

그런 다음 인덱스가 숫자이고 배열이 희박하지 않은 경우 연관 배열을 사용하여 2D 배열을 가짜로 만들고 수동으로 반복하여 인덱스를 반복할 수 있습니다.

declare -A a
a[1,1]="1-1V"

a[2,1]="2-1V"
a[2,2]="2-2V"

a[3,1]="3-1V"
a[3,2]="3-2V"
a[3,3]="3-3V"

x=3
i=1
while [[ ${a[$x,$i]+set} == set ]]; do
    echo "${a[$x,$i]}"
    ((i++))
done

(물론 "존재하지 않음" 요소를 특정 값으로 설정한 다음 루프 내에서 해당 값을 무시하여 희소 배열을 시뮬레이션할 수 있습니다.)

Ksh는 실제로 2D 배열 또는 최소한 중첩 목록도 지원합니다.

a[1][1]="1-1V"

a[2][1]="2-1V"
a[2][2]="2-2V"

a[3][1]="3-1V"
a[3][2]="3-2V"
a[3][3]="3-3V"

x=3
for x in "${a[x][@]}"; do
    echo "$x"
done

이것이 작동하지 않더라도:

for x in "${a[@][1]}"; do
    echo "$x"
done

그러나 복잡한 데이터 구조에 대한 필요성은 셸에서 다른 프로그래밍 언어로 전환하는 것을 고려하는 것이 유용할 수 있는 상황 중 하나입니다.

${!array[*]}어떠한 경우에도 , 또는 ${!array[@]}( 포함 또는 제외 !)을 사용하면 안 됩니다 . "${!array[@]}"그 반대입니다. 공백이 포함된 값을 그대로 유지하는 유일한 방법이기 때문입니다. 예 z=("foo bar" "zoom")를 들어 다음을 사용하여 for x in ${z[*]}; do echo $x; done동일한 것과 비교하십시오."${z[*]}""${z[@]}"

관련 정보