배열

배열 에서 Bash

{other: "%{count}개의 연습 문제"}

배열 소개

Bash는 두 가지 유형의 매개변수를 제공해요: "스칼라" 값과 배열이에요. 스칼라 값은 문자열이나 숫자가 될 수 있고, 단일한 "것"을 나타내요.

대부분의 경우 스칼라 값만으로 데이터를 담기에 충분해요. 하지만 때로는 스칼라 값 여러 개를 저장해야 할 때가 있어요. 이럴 때는 배열 을 사용해요.

배열에는 두 가지 종류가 있어요:

  • 숫자로 인덱싱되는 배열은 정수 키를 문자열 값에 대응시켜요. (다른 언어에서는 이것을 "리스트"나 "시퀀스"라고 부를 수도 있어요.)
  • 연관 배열은 문자열 키를 문자열 값에 대응시켜요. (다른 언어에서는 "맵"이나 "딕셔너리"라고 부를 수도 있어요.)

이 문서의 처음 몇 개 절에서는 숫자로 인덱싱되는 배열(이하 간단히 "배열")을 다뤄요. 연관 배열에 대한 자세한 내용은 마지막에 나와요.

Caution

Bash 배열은 스칼라 값_만_ 저장할 수 있어요. 2차원 배열(배열의 배열)을 만드는 방법은 없어요.

배열 변수 선언하고 초기화하기

괄호로 묶은 원소들(비어 있을 수도 있어요)을 변수에 대입하면 배열을 초기화할 수 있어요.

myarray=("one" "two" "three")

모든 변수 대입에서 그렇듯이, 등호 주위에는 공백이 없어야 해요.

원소 사이에 쉼표 구분자가 없다는 점에 유의해요. 공백으로 구분된 문자열들이에요.

사실 괄호 안의 공백 양은 전적으로 자유예요. 줄바꿈도 허용되니, 가독성을 높이고 싶은 만큼 얼마든지 사용해요.

myarray=(
    "first element"
    "second element"
    "this is the last element"
)

이런 방식으로 문자열 여러 개를 배열 변수에 대입하면 첫 번째 문자열은 인덱스 0에, 다음 문자열은 인덱스 1에, 그다음은 인덱스 2에, 이런 식으로 저장돼요.

필요한 인덱스를 지정해서 "희소 배열"을 초기화할 수도 있어요.

raindrops=([3]="Pling" [5]="Plang" [7]="Plong")
Note

다시 강조하면, 배열 인덱스는 0부터 시작해요. 이 코드 조각은 "true"를 출력해요:

myarray=("one" "two" "three")
[[ "${myarray[0]}" == "one" ]] && echo true || echo false

declare 명령(local은 함수 안에서)을 사용해서 변수가 배열을 담을 것이라고 지정할 수 있어요.

declare -a myarray

그냥 괄호로 묶은 원소들(비어 있어도 돼요)을 대입해서 변수를 초기화하는 편이 더 관용적이에요.

배열의 원소에 접근하기

위의 노트에서 봤듯이, 배열 원소에 접근할 때는 ${myarray[$index]} 문법을 사용해요. 인덱스는 대괄호 안에 넣어요. 중괄호는 반드시 필요해요.

Note

숫자로 인덱싱되는 배열에서 인덱스는 산술 표현식이에요. Bash 매뉴얼은 다음과 같이 설명해요:

산술 표현식 안에서는 셸 변수를 매개변수 확장 문법을 사용하지 않고 이름으로 참조할 수도 있어요.

즉, "단순한" 변수 확장에는 $가 필요하지 않아요. 다음처럼 원소에 접근할 수 있는데, 조금 더 읽기 쉬워요:

i=5
echo "${myarray[i]}"
# ..............^

주어진 인덱스가 배열에 없으면, 확장 결과는 빈 문자열이에요.

배열에 값 대입하기

특정 배열 항목에 값을 대입하려면 다음 문법을 사용해요:

myarray[10]="hello"

배열에 값을 덧붙이려면 += 연결 대입 연산자를 사용하고, 괄호를 함께 써요:

myarray+=("new element 1" "new element 2")

배열 순회하기

보통 배열의 값 을 순회해야 할 때가 많아요. 반복 개념에서 본 for문을 사용해요:

myarray=("one" "two" "three")
for value in "${myarray[@]}"; do
    echo "$value"
done

배열을 확장하는 특별한 문법인 "${myarray[@]}"에 유의해요. 이 매개변수 확장 형태는 배열 값을 각각 별개의 단어로 치환해요. 다음과 어느 정도 같아요:

for value in "${myarray[0]}" "${myarray[1]}" ... "${myarray[n]}"

"${myarray[@]}" 형태는 희소 배열에서도 동작하며, 정의된 값만 확장해요.

인덱스가 @ 기호인 이 특별한 확장은 큰따옴표 안에서만 특별하게 동작해요.

그 밖의 특별한 매개변수 확장

배열을 순회할 때 필요한 특별한 문법이 몇 가지 더 있어요. 이들은 매뉴얼의 셸 매개변수 확장에 설명되어 있어요.

배열의 길이 를 구하려면 이름 앞에 #을 붙인 ${#myarray[@]}를 사용해요. 배열의 "길이"는 배열에 들어 있는 원소의 개수를 뜻해요.

배열의 인덱스 들을 얻으려면 이름 앞에 !를 붙이고 확장을 큰따옴표로 감싼 "${!myarray[@]}"를 사용해요. 숫자로 인덱싱되는 배열에서는 인덱스가 숫자 순서대로 확장돼요.

배열 인덱스 순회하기

값뿐만 아니라 인덱스도 필요할 때가 있어요. 이를 위한 방법이 몇 가지 있어요.

  1. 인덱스가 끊김 없이 이어지는 것을 알고 있다면, 산술 for문을 사용할 수 있어요.

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

    배열 이름 앞에 # 문자가 붙은 ${#myarray[@]} 문법에 유의해요. 배열은 0부터 시작하는 인덱싱을 사용하므로, 배열의 마지막 인덱스는 배열 길이보다 하나 작아요.

  2. 배열이 희소할 때는 다음 형태를 사용할 수 있어요:

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

    배열 이름 앞에 ! 문자가 붙은 ${!myarray[@]} 문법에 유의해요.

배열 살펴보기

배열의 내용을 보고 싶다면 declare 명령에 -p 옵션을 붙여서 사용해요:

a=("the 'first' element"
   second
   third
   'the "last" element')
declare -p a

이렇게 하면 표준적인 셸 인용 형식으로 내용을 출력해요.

declare -a a=([0]="the 'first' element" [1]="second" [2]="third" [3]="the \"last\" element")

연관 배열

다시 말하면, 연관 배열은 숫자가 아니라 문자열을 인덱스로 사용해요. 위에 쓴 모든 내용은 연관 배열에도 적용되지만, 몇 가지 작은 차이가 있어요. 일반적으로 "인덱스"가 아니라 "키"라는 용어를 사용해요. 연관 배열은 키를 값에 대응시켜요.

연관 배열 선언하기

일반 배열과 달리, 연관 배열은 반드시 선언해야 해요. declare에 -A 옵션을 사용해요(함수 안에서는 local):

declare -A mymap

myfunc() {
    local -A my_local_map
    # ...
}

연관 배열 초기화하기

키-값 쌍은 괄호 안에 지정해요:

mymap=([first]=foo [second]=bar [third]=baz)
declare -p mymap

이렇게 하면 다음이 출력돼요:

declare -A mymap=([second]="bar" [first]="foo" [third]="baz")
Note

연관 배열은 순서가 없어요.

선언과 초기화를 한 줄에서 함께 할 수 있어요.

declare -A mymap=([first]=foo [second]=bar [third]=baz)

최근 Bash 버전에서는 초기화에 (key value key value ...) 형태를 사용할 수 있어요.

declare -A mymap=(first foo second bar third baz)

값에 접근하기

원소에 접근할 때는 앞과 같은 문법을 사용해요: ${mymap[$key]}.

연관 배열의 키는 산술 문맥에서 평가되지 않아요. 일반적인 매개변수 확장 문법이 필요해요.

연관 배열에 대입하기

대입은 앞과 같은 문법을 사용해요:

mymap[$key]="$value"

순회하기

for value in "${mymap[@]}" 루프로 순회할 수 있어요. 하지만 보통은 값과 함께 키도 필요해요.

위에서 본 "${!mymap[@]}" 문법을 사용해요.

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

이렇게 하면 다음이 출력돼요

second -> bar
first -> foo
third -> baz

다시 강조하면, 키에는 순서가 없어요.

GitHub에서 편집 링크가 새 창이나 탭에서 열려요