두 배열의 동일한 인덱스에 있는 값을 동시에 에코

두 배열의 동일한 인덱스에 있는 값을 동시에 에코

Bash 스크립트에서 동시에 처리하려는 배열이 2개 있습니다. 첫 번째 배열에는 일종의 레이블이 포함되어 있습니다. 두 번째 배열에는 아래와 같은 값이 포함됩니다.

LABELS=(label1 label2 label3 labe4 )
VALUES=(91 18 7 4)

필요한 것: 다음과 같이 LABELS 배열의 인덱스 항목과 VALUES 배열의 해당 항목 값 앞에 에코하는 루프입니다.

label1 91
label2 18
label3 7
label4 4

중첩 루프가 작동하지 않는 것 같아요. 아래에서 시도했지만 구문에 따르면 작동하지 않습니다.

for label in {LABELS[@]} && value in {VALUES[@]}
do
    echo ${label} ${value}
done

답변1

숫자 인덱싱을 사용하고 인덱스로 배열 요소를 참조하십시오.

labels=(label1 label2 label3 label4)
values=(91 18 7 4)


for((i=0; i<"${#labels[@]}"; i++ )); do
  printf '%s: %s\n' "${labels[i]}" "${values[i]}"
done

또는 상대적으로 새로운(>= 버전 4) bash 또는 연관 배열을 지원하는 다른 셸을 사용하는 경우 단일 배열을 사용할 수 있습니다.

declare -A values=( ["label1"]=91 ["label2"]=18 \
                    ["label3"]=7 ["label4"]=4 )

for label in "${!values[@]}"; do
  printf '%s: %s\n' "$label" "${values[$label]}"
done

쉘 스크립트에서 로컬 변수에 대문자를 사용하는 것은 나쁜 습관이고 전역 환경 변수는 관례적으로 대문자로 표시되기 때문에 스크립트에서 대문자를 사용하면 변수 이름 충돌이 발생할 수 있기 때문에 변수 이름을 소문자로 변경했습니다.

답변2

두 배열 모두 정확히 동일한 인덱스(0, 1, 2, 3)를 가지므로 ${!array[@]}배열 중 하나의 인덱스(키라고도 함)를 반복하고 해당 반복자를 사용하여 두 배열의 값에 액세스할 수 있습니다.

이는 "인덱스 배열"(즉, 정수 인덱스) 및 "연관 배열"(문자열 인덱스)에 작동합니다.

예를 들어

LABELS=(label1 label2 label3 labe4 )
VALUES=(91 18 7 4)

for i in "${!LABELS[@]}"; do
  echo "${LABELS[i]}" "${VALUES[i]}"
done

산출:

label1 91
label2 18
label3 7
labe4 4

그런데 이와 같은 루프를 사용하여 연관 배열을 채울 수도 있습니다. 이는 수동으로 정의된 두 배열과 같이 키와 값을 동시에 읽을 수 없는 경우에 유용합니다.

LABELS=(label1 label2 label3 labe4)
VALUES=(91 18 7 4)

declare -A LV # declare LV to be an associative array

for i in "${!LABELS[@]}"; do
  LV["${LABELS[$i]}"]="${VALUES[$i]}";
done

declare -p LV

산출:

declare -A LV=([labe4]="4" [label3]="7" [label2]="18" [label1]="91" )

이제부터 스크립트는 $LV연관 배열을 사용하여 키의 값에 직접 액세스할 수 있습니다.

$ echo "${LV[label1]}"
91

@terdon 및 @NickMatteo의 답변(0에서 배열 길이까지 반복)과 같은 C 스타일 for 루프를 사용할 수도 있지만 이는 배열 인덱스가 숫자이고 연속적이며 배열에 간격이 없는 경우에만 작동합니다( 정의되지 않은 인덱스)가 효과적입니다.

대부분의 경우 이것은 괜찮습니다. 왜냐하면 배열은 종종연속적인 인덱스 번호로 정의되지만 다른 경우에는 예상대로 작동하지 않습니다. 예를 들어 $array인덱스가 1, 3, 5, 7, 11, 13, ${#array[@]}17, 7에 대해 정의된 경우 반환되고 이러한 루프가 시작됩니다. 0부터 반복을 시작합니다. .6 (또는 <=대신 <테스트 조건으로 사용하는 경우 0..7) 배열의 실제 인덱스 목록 대신.

예를 들어:

$ for i in 1 3 5 7 11 13 17 ; do let array[$i]=$i*$i ; done

$ declare -p array
declare -a array=([1]="1" [3]="9" [5]="25" [7]="49" [11]="121" [13]="169" [17]="289")

$ echo "${#array[@]}"
7

$ for ((i=0; i<"${#array[@]}"; i++)); do echo $i: "${array[$i]}" ; done
0: 
1: 1
2: 
3: 9
4: 
5: 25
6: 

$ echo "${!array[@]}"
1 3 5 7 11 13 17

$ for i in "${!array[@]}"; do echo $i: "${array[$i]}"; done
1: 1
3: 9
5: 25
7: 49
11: 121
13: 169
17: 289

답변3

인덱스를 반복하면 됩니다. 예를 들어

for (( i = 0; i < "${#LABELS[@]}"; i++ ))
do echo "${LABELS[$i]} ${VALUES[$i]}"
done

또한 다음 과 같은 더 많은 서식 컨트롤을 echo사용할 수도 있습니다.printf

printf '%6s: %3d\n' "${LABELS[$i]}" "${VALUES[$i]}"

최대 6글자, 최대 3자리 숫자로 라벨을 배열하세요.

답변4

그럴 필요가 없고 배열 압축 연산자를 사용하는 사람들 bash을 위해 zsh:${arrayA:^arrayB}

$ labels=(label1 label2 label3 labe4 )
$ values=(91 18 7 4)
$ for k v (${labels:^values}) print -r -- "$k => $v"
label1 => 91
label2 => 18
label3 => 7
labe4 => 4

루프가 필요하지 않더라도:

$ print -raC2 -- ${labels:^values}
label1  91
label2  18
label3  7
labe4   4

print그들은 기둥에 r십자가 표시를 만들었습니다 .a2 C

$ printf '%6s => %d\n' ${labels:^values}
label1 => 91
label2 => 18
label3 => 7
 labe4 => 4

그러나 여기에서는 다음과 같이 할 수도 있습니다.

$ print -rC2 -- $labels $values
label1  91
label2  18
label3  7
labe4   4

print두 어레이 모두 에 대해 olumn r에 대해 설명합니다 2 C(여기에서는 생략됨 -a).

이 두 배열을 사용하여 연관 배열을 만들 수 있다는 점에 유의하세요(여기서 더 의미가 있는 것처럼 들립니다).

typeset -A assoc
assoc=( ${labels:^values} )

레이블이나 값에 빈 문자열이 포함될 수 있는 경우 다음을 사용하는 것이 좋습니다.

assoc=( "${(@)labels:^values}" )

그들을 보호하기 위해.

그런 다음:

print -raC2 -- ${(kv)assoc}

편의를 위해 print k열을 교차하거나 빈 키/값을 남겨두세요.vra2 C

print -raC2 -- "${(@kv)assoc}"

또는:

for key value ("${(@kv)assoc}") print -r -- "$key => value"

또는:

for key ("${(@k)assoc}") print -r -- "$key => $assoc[$key]"

그러나 연관 배열 항목이 확장되는 순서는 지정되지 않습니다.

관련 정보