아래와 같이 연관 배열을 만들었습니다. 몇 가지 세부 정보를 제공하기 위해 키는 특정 파일을 참조합니다. 더 큰 스크립트의 컨텍스트에서 이 배열을 사용할 것이기 때문입니다(파일이 포함된 디렉터리는 getopts 매개 변수가 됩니다).
declare -A BAMREADS
echo "BAMREADS array is initialized"
BAMREADS[../data/file1.bam]=33285268
BAMREADS[../data/file2.bam]=28777698
BAMREADS[../data/file3.bam]=22388955
echo ${BAMREADS[@]} # Output: 22388955 33285268 28777698
echo ${!BAMREADS[@]} # Output: ../data/file1.bam ../data/file2.bam ../data/file3.bam
지금까지 이 배열은 내가 예상한 대로 작동하는 것 같습니다. 이제 이 배열을 기반으로 또 다른 연관 배열을 만들고 싶습니다. 구체적으로 말하면, 두 번째 배열은 첫 번째 배열과 동일한 키를 갖지만 $MIN이라는 변수로 값을 나누고 싶습니다.
다음 전략 중 어느 것이 가장 좋은지 잘 모르겠고 둘 중 어느 것도 제대로 작동하지 않는 것 같습니다.
전략 1:배열을 복사하고 배열을 수정하시겠습니까?
MIN=33285268
declare -A BRAMFRACS
echo "BAMFRACS array is initialized"
BAMFRACS=("${BAMREADS[@]}")
echo ${BAMFRACS[@]} # Output: 22388955 33285268 28777698
echo ${!BAMFRACS[@]} # Output: 0 1 2
이것은 내가 원하는 열쇠가 아닙니다. 작동하더라도 모든 값에 대해 언급한 작업을 수행해야 합니다.
전략 2: 첫 번째 배열을 반복하면서 두 번째 배열을 구성합니다.
MIN=33285268
declare -A BRAMFRACS
echo "BAMFRACS array is initialized"
for i in $(ls $BAMFILES/*bam)
do
echo $i
echo ${BAMREADS[$i]}
BAMFRACS[$i] = ${BAMREADS[$i]}
done
echo ${BAMFRACS[@]}
echo ${!BAMFRACS[@]}
#When I run this, I get the following error which I am unsure how to solve:
../data/file1.bam
33285268
script.bash: line 108: BAMFRACS[../data/file1.bam]: No such file or directory
../data/file2.bam
28777698
script.bash: line 108: BAMFRACS[../data/file2.bam]: No such file or directory
../data/file3.bam
22388955
script.bash: line 108: BAMFRACS[../data/file3.bam]: No such file or directory
감사해요
답변1
연관 배열 복사에 대한 보다 일반적인 질문에 대답합니다.
관리자가 4.0에서 자체 연관 배열을 도입했을 때 bash
zsh API 대신 ksh93 API를 복사하는 불행한 결정을 내렸습니다.
ksh93
/ bash
는 연관 배열 설정을 전체적으로 지원하지만 다음과 일치하지 않습니다.
hash=([k1]=v1 [k2]=v2)
통사론. 시간이 지나면 zsh
그렇죠
hash=(k1 v1 k2 v2)
( ([k]=v...)
ksh93 구문에 대한 지원은 나중에 호환성을 위해 추가되었습니다).
그러나 이는 ksh93 및 bash를 사용하여 임의의 키 및 값 목록에서 해시를 생성하는 것이 매우 까다롭다는 것을 의미합니다.
zsh
구문을 사용하면 목록을 키와 값이 교대로 전달되기만 하면 됩니다. 예를 들어 두 개의 연관 배열을 복사하려면 다음을 수행하십시오.
h2=("${(@kv)h1}")
또는 두 개의 열이 있는 CSV에서:
IFS=$'\n,'; h=($(<file.csv))
또는 키와 값의 배열에서:
h=("${(@)keys:^values}")
ksh93
/ 구문을 사용할 bash
때 키와 값 목록(예: 및 in )으로 확장할 수 있는 "${!h[@]}"
and 가 있지만 원하는 구문의 (in) 키와 값으로 확장할 수 있는 연산자는 없습니다 ."${h[@]}"
"${(@k)h}"
"${(@v)h}"
zsh
[key]=value
h=(...)
"${(@kv)h}"
zsh
루프의 요소를 복사하는 대신 연관 배열을 복사하기 위해 이러한 셸에서 사용할 수 있는 한 가지 방법은 typeset -p
.
예를 들어 다음을 사용하여 복사와 동일한 작업을 zsh
수행할 수 있습니다.h2=("${(@kv)h1}")
h1
h2
ksh93
bash
h1_definition=$(typeset -p h1) &&
eval "typeset -A h2=${h1_definition#*=}"
bash
다음과 같이 단축할 수 있습니다 .
h1_definition=$(typeset -p h1) &&
typeset -A h2="${h1_definition#*=}"
(ksh93에서와 같이 typeset -A h=value
in의 약어이지만, 시작하고 끝나는 경우 내용은 (참조되거나 일부 확장의 결과인 경우에도) 전달된 것처럼 복합 연관 할당으로 해석됩니다.typeset -A h=([0]=value)
bash
value
(
)
eval
(
마지막으로 루프를 사용하는 것도 쉽습니다.
for k in "${!h1[@]}"; do h2[$k]=${h1[$k]}; done
답변2
이전 배열에서 새 배열을 만듭니다.
MIN=33285268
declare -A BRAMFRACS
for key in "${!BAMREADS[@]}"; do
BRAMFRACS[$key]=$(( ${BAMREADS[$key]} / MIN ))
done
코드에 대한 의견:
첫 번째 제안 코드가 복사되었기 때문에 작동하지 않습니다.가치연관 배열에서 새 배열로. 이러한 값은 자동으로 키 0, 1, 2를 가져오지만 원래 키는 복사되지 않습니다. 위에 표시된 대로 키별로 배열을 복사해야 합니다. 이렇게 하면 올바른 키에 원하는 값을 할당할 수 있습니다.
=
두 번째 제안 코드에는 할당 주위에 공백이 있기 때문에 구문 오류가 있습니다 . 여기서 보고 있는 오류가 발생합니다. "피연산자를 사용하여 실행되는 명령variable = value
"으로 해석됩니다.variable
=
value
일련의 경로 이름을 반복하려면 다음을 수행하십시오.사용하지 마세요
ls
. 대신for pathname in "$BAMFILES"/*bam; do
.변수 확장을 인용해 보세요.
가변 데이터를 출력하는
printf
대신 사용을 고려하십시오 .echo
관련된:
답변3
다음 bash는 연관 배열 AA2(설정되지 않을 수 있음)의 값을 다른 연관 배열 AA1(대부분 -A로 선언해야 함)에 할당합니다.
LIST="$(declare -p AA2 2>/dev/null)"
[[ "$LIST" ]] && AA1+=${LIST#*=}
declare -p
변수 값을declare
명령문으로 에코하는 것은 단어 분할 문제 없이 인터프리터에 직접 전달될 수 있습니다.${LIST#*=}
등호와 그 앞의 모든 것을 제거합니다.- 0이 아닌 길이 테스트(
2>/dev/null
) 중에 오류( )를 숨기면 AA2 설정을 해제할 수 있습니다.declare
[[ "$LIST" ]]
- AA1 또는 AA2가 연관 배열이 아닌 경우 예기치 않은 결과(오류 아님)가 발생합니다.
답변4
이렇게 하면 트릭을 수행할 수 있습니다(추가 키 값도 추가할 수 있음).
declare -A origDict=( [keya]=value_a [keyb]=value_b [keyc]=value_c )
declare -a newDict=( echo ${origDict[*]} [keynew]=new_value )