backend/ubuntu

The linux command line - 35. array

seul chan 2021. 7. 25. 18:37

35. Array

지금까지 살펴본 변수는 단일 값을 포함하는 스칼라 변수. 이번 장에서는 여러 값을 보유하는 array 데이터 구조를 살펴보고 쉘에서 이를 다루는 방식을 정리.

What is array?

배열은 한 번에 둘 이상의 값을 보유하는 변수.

대부분의 프로그래밍 언어는 다차원 배열을 지원하지만 bash의 배열은 단일 차원으로 제한됨.

bash 2에서 처음 array를 지원. sh에서는 array를 지원하지 않음.

Create array

array 변수는 다른 bash 변수와 마찬가지로 이름이 지정

[me@linuxbox ~]$ a[1]=foo
[me@linuxbox ~]$ echo ${a[1]}
foo

declare를 사용해서 만들수도 있음.

[me@linuxbox ~]$ declare -aa

Assigning values to an array

두가지 방법으로 할당 가능.

name[subscript]=value

name은 array의 이름이며 subscript는 0 이상의 정수. (첫 번째 인자는 subscript 0부터 시작)

name=(value1 value2...)

아래와 같이 만들 수 있음.

[me@linuxbox ~]$ days=(Sun Mon Tue Wed Thu Fri Sat)

특정 subscriptㅌ와 함께 값을 지정 할 수도 있다.

[me@linuxbox ~]$ days=([0]=Sun [1]=Mon [2]=Tue [3]=Wed [4]=Thu [5]=Fri [6]=Sat)

Accessing Array elements

array는 언제 사용하면 좋을까? 여러 데이터를 다루는 태스크나 spreadsheet 프로그램에서 사용 가능.

간단한 데이터 수집 예제를 만들어 보자.

저장된 디렉토리에 있는 파일의 수정 시간을 검사하는 스크립트. 각 파일이 마지막으로 수정된 시간을 보여주는 테이블을 출력

[me@linuxbox ~]$ hours .
Hour  Files  Hour  Files
----  -----  ----  -----
00    0      12    11
01    1      13    7
02    0      14    1
03    0      15    7
04    1      16    6
05    1      17    5
06    6      18    4
07    3      19    4
08    1      20    1
09    14     21    0
10    2      22    0
11    5      23    0

Total files = 80

위 코드는 다음과 같음.

#!/bin/bash

# hours: script to count files by modification time

usage () {
      echo "usage: ${0##*/} directory" >&2
}

# check that argument is a directory

if [[ ! -d "$1" ]]; then
    usage
    exit 1
fi

# Initialize array
for i in {0..23}; do hours[i]=0; done

# Collect data
for i in $(stat -c %y "$1"/* | cut -c 12-13); do
      j="${i#0}"
      ((++hours[j]))
      ((++count))
done

# Display data
echo -e "Hour\tFiles\tHour\tFiles"
echo -e "----\t-----\t----\t-----"
for i in {0..11}; do
      j=$((i + 12))
      printf "%02d\t%d\t%02d\t%d\n" \
            "$i" \
            "${hours[i]}" \
            "$j" \
            "${hours[j]}"
done
printf "\nTotal files = %d\n" $count

Array operation

array를 제거하거나, 개수를 세거나 정렬하는 등 많은 공통적인 array operation을 지원한다.

Outputting the entire contents of an array

*@ subscipt는 array의 모든 element에 접근할 수 있게 해준다. positional parameter로 @가 더 유용하게 쓰임.

[me@linuxbox ~]$ animals=("a dog" "a cat" "a fish")
[me@linuxbox ~]$ for i in ${animals[*]}; do echo $i; done
a
dog
a
cat
a
fish
[me@linuxbox ~]$ for i in ${animals[@]}; do echo $i; done
a
dog
a
cat
a
fish
[me@linuxbox ~]$ for i in "${animals[*]}"; do echo $i; done
a dog a cat a fish
[me@linuxbox ~]$ for i in "${animals[@]}"; do echo $i; done
a dog
a cat
a fish

Determining the Number of Array Elements

parameter extension을 사용해서 array가 가진 수를 셀 수 있다.

[me@linuxbox ~]$ a[100]=foo
[me@linuxbox ~]$ echo ${#a[@]}  # number of array elements
1
[me@linuxbox ~]$ echo ${#a[100]}  # length of element 100
3

Finding the Subscripts Used by an Array

어떤 element가 array에 있는지 결정하는 것도 유용하게 쓰일 수 있다. 아래 문법으로 사용

${!array[*}}
${!array[@}}
[me@linuxbox ~]$ foo=([2]=a [4]=b [6]=c)
[me@linuxbox ~]$ for i in "${foo[@]}"; do echo $i; done
a
b
c
[me@linuxbox ~]$ for i in "${!foo[@]}"; do echo $i; done
2
4
6

Adding Elements to the End of an Array

+= operator 를 사용해서 array에 값을 추가할 수 있다.

[me@linuxbox ~]$ foo=(a b c)
[me@linuxbox ~]$ echo ${foo[@]}
a b c
[me@linuxbox ~]$ foo+=(d e f)
[me@linuxbox ~]$ echo ${foo[@]}
a b c d e f

Sorting an Array

쉘에서는 array를 정렬하는 기능을 바로 제공하지 않지만 약간의 코드로 쉽게 구현할 수있다.

#!/bin/bash

# array-sort: Sort an array

a=(f e d c b a)

echo "Original array: ${a[@]}"
a_sorted=($(for i in "${a[@]}"; do echo $i; done | sort))
echo "Sorted array:   ${a_sorted[@]}"

이를 실행하면 다음과 같음.

[me@linuxbox ~]$ array-sort
Original array: f e d c b a
Sorted array:   a b c d e f

Deleting an Array

array를 제거하기 위해서는 unset 명령어를 사용하면 된다.

[me@linuxbox ~]$ foo=(a b c d e f)
[me@linuxbox ~]$ echo ${foo[@]}
a b c d e f
[me@linuxbox ~]$ unset foo
[me@linuxbox ~]$ echo ${foo[@]}

[me@linuxbox ~]$

이는 각각의 element에도 사용 가능.

[me@linuxbox ~]$ foo=(a b c d e f)
[me@linuxbox ~]$ echo ${foo[@]}
a b c d e f
[me@linuxbox ~]$ unset 'foo[2]'
[me@linuxbox ~]$ echo ${foo[@]}
a b d e f

흥미로운 점은 기존에 존재하는 array 변수에 empty value를 할당해도 array 자체가 제거되는 것은 아니다.

[me@linuxbox ~]$ foo=(a b c d e f)
[me@linuxbox ~]$ foo=
[me@linuxbox ~]$ echo ${foo[@]}
b c d e f

subscript가 없이 array를 사용하면 array의 첫번째 element를 지칭하게 되기 때문.

[me@linuxbox ~]$ foo=(a b c d e f)
[me@linuxbox ~]$ echo ${foo[@]}
a b c d e f
[me@linuxbox ~]$ foo=A
[me@linuxbox ~]$ echo ${foo[@]}
A b c d e f

Associative Arrays

bash 4.0 이상에서는 associative array를 제공한다. 이는 array index로 integer 대신에 string을 사용한다.

declare -A colors
colors["red"]="#ff0000"
colors["green"]="#00ff00"
colors["blue"]="#0000ff"