쉘 스크립트의 연관 배열


10

쉘 스크립트에서 연관 배열을 구현하는 트릭을 보았습니다. 예를 들어 key = apples print array["apples"]로 스크립트 를 작성할 수 있습니다 echo \$array$key.

그러나 배열을 반복하기 위해 키를 생성하는 방법에 대한 언급은 없습니다. 내가 생각할 수있는 유일한 방법은 공백으로 구분 된 변수에 키를 저장하여 for 루프를 사용하여 배열을 반복하는 것입니다.

나중에 사용할 수 있도록 키를 저장하는 다른 방법이 있습니까?


5
쉘 스크립트에서 연관 배열을 사용하려는 경우 프로젝트가 쉘 스크립트에 비해 너무 복잡 할 수 있습니다. :)
Martin von Wittich

@MartinvonWittich 왜? 가능한 3 가지 DB 스키마 중 하나에서 SQL 스크립트를 실행하는 쉘 스크립트가 있습니다. 필수 스키마는 파일 이름에 약어와 함께 포함됩니다. 이 약어와 실제 스키마 이름 간의 매핑이 필요합니다. 실제 스키마 이름 (약어 아님)을 고려하면 연관 배열보다 나은 방법은 환경마다 다를 수 있으므로 배열 변수 (값을 한 번만 설정할 수 있음)가 완벽합니다.
Slav

2
@Slav 나는 복잡한 배열이 아니라 복잡한 스크립트가 필요한 쉘 스크립트에 대해서만 논쟁하지 않는다. 그러나 그것은 나의 개인적인 취향 일뿐입니다. 나는 종종 쉘 스크립트를 작성하기 시작한 다음 특정 복잡도 임계 값을 초과한다는 것을 알게되면 즉시 Perl로 다시 작성합니다.
Martin von Wittich

답변:


19

연관 배열이있는 쉘

일부 최신 쉘은 연관 배열을 제공합니다 : ksh93, bash ≥4, zsh. ksh93 및 bash에서 a연관 배열 인 경우 "${!a[@]}"해당 키의 배열입니다.

for k in "${!a[@]}"; do
  echo "$k -> ${a[$k]}"
done

zsh에서 해당 구문은 ksh 에뮬레이션 모드에서만 작동합니다. 그렇지 않으면 zsh의 기본 구문을 사용해야합니다.

for k in "${(@k)a}"; do
  echo "$k -> $a[$k]"
done

${(k)a}a빈 키가없는 경우에도 작동합니다 .

zsh에서는 ey kvalues를 동시에 반복 할 수도 있습니다 .

for k v ("${(@kv)a}") echo "$k -> $v"

연관 배열이없는 쉘

연관 배열이없는 쉘에서 연관 배열을 에뮬레이트하는 것이 훨씬 더 많은 작업입니다. 연관 배열이 필요한 경우 ksh93 또는 Perl과 같은 더 큰 도구를 가져와야 할 때입니다.

단순한 POSIX 쉘에 연관 배열이 필요한 경우 키가 문자 0-9A-Z_a-z(ASCII 숫자, 문자 및 밑줄) 만 포함하도록 제한 될 때이를 배열하는 방법이 있습니다 . 이 가정 하에서 키는 변수 이름의 일부로 사용될 수 있습니다. 아래 함수는 두 개의 연속 밑줄을 포함해서는 안되는 이름 지정 접두사 "줄기"로 식별되는 배열에서 작동합니다.

## ainit STEM
## Declare an empty associative array named STEM.
ainit () {
  eval "__aa__${1}=' '"
}
## akeys STEM
## List the keys in the associatve array named STEM.
akeys () {
  eval "echo \"\$__aa__${1}\""
}
## aget STEM KEY VAR
## Set VAR to the value of KEY in the associative array named STEM.
## If KEY is not present, unset VAR.
aget () {
  eval "unset $3
        case \$__aa__${1} in
          *\" $2 \"*) $3=\$__aa__${1}__$2;;
        esac"
}
## aset STEM KEY VALUE
## Set KEY to VALUE in the associative array named STEM.
aset () {
  eval "__aa__${1}__${2}=\$3
        case \$__aa__${1} in
          *\" $2 \"*) :;;
          *) __aa__${1}=\"\${__aa__${1}}$2 \";;
        esac"
}
## aunset STEM KEY
## Remove KEY from the associative array named STEM.
aunset () {
  eval "unset __aa__${1}__${2}
        case \$__aa__${1} in
          *\" $2 \"*) __aa__${1}=\"\${__aa__${1}%%* $2 } \${__aa__${1}#* $2 }\";;
        esac"
}

(경고, 테스트되지 않은 코드. 구문 상 유효하지 않은 스템 및 키에 대한 오류 감지는 제공되지 않습니다.)


5

상점의 의미를 잘 모르겠지만 ${!array[@]}구문을 사용하여 키를 반복 할 수 있습니다 .

$ typeset -A foo=([key1]=bar [key2]=baz);
$ echo "${!foo[@]}" 
key2 key1

따라서 반복하려면

$ for key in "${!foo[@]}"; do echo "$key : ${foo[$key]}"; done
key2 : baz
key1 : bar

나는이에 좋은, 짧은 튜토리얼을 발견 여기에 .


아래 주석에서 지적했듯이 연관 배열이 bash버전 4에 추가되었습니다 . 주제에 대한 Linux 저널 기사는 여기 를 참조 하십시오 .


1
(bash version 4 only)중요한 점입니다. 일반적으로 bash배열은 숫자 만입니다.
Ricky Beam

1
당신 의 예제 typeset대신에 사용하고 싶을 수도 있습니다 declare. 그것은 bash 4와 ksh93 사이에서 이식성이 뛰어나서 처음으로 쉘 연관 배열을 구현했습니다.
jlliagre

0

연관 배열이없는 쉘

키가 [0-9A-Za-z_](숫자, 문자, 밑줄) 로 제한되어 있어도 어렵지 않습니다 .

트릭은 array [ $ key ] 에 저장하는 대신 변수 array_ $ key에 저장하는 것 입니다.

세트:

eval "array_$key='$value'"

가져 오기:

value=`eval echo '$'array_$key`

참고 : 값은 '작은 따옴표를 포함 할 수 없습니다 .


-1

이것은 bash에서 작동합니다.

cert="first"
web="second"
declare -A assoc_array=(["cert"]="${cert}" ["web"]="${web}")
echo "first is" ${assoc_array[cert]}
echo "second is" ${assoc_array[web]}

또는

#loop
for i in "${assoc_array[@]}"
do
   echo "$i"
done

eval afaik을 사용할 필요가 없습니다


질문의 요점을 놓쳤다 고 생각합니다.
G-남자
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.