배열(Array)은 동일한 타입 또는 서로 다른 타입의 여러 값을 담을 수 있는 변수입니다. 배열에는 크기 제한이 없으며, 멤버 변수가 반드시 연속된 인덱스로 할당되어야 한다는 규칙도 없습니다. 배열 인덱스는 0부터 시작합니다.
이 글에서는 Bash에서 활용할 수 있는 15가지 배열 연산 방법을 예제와 함께 살펴봅니다. Bash 스크립팅이 처음이라면 Bash 스크립팅 입문 튜토리얼부터 먼저 확인해 보시길 권장합니다.
1. 배열 선언과 값 할당
Bash에서는 변수를 다음과 같은 형식으로 사용하면 자동으로 배열이 생성됩니다.
name[index]=value
- name: 임의로 지정할 수 있는 배열 이름
- index: 0 이상의 숫자로 평가되는 숫자 또는 표현식.
declare -a arrayname명령으로 명시적으로 배열을 선언할 수도 있습니다.
$ cat arraymanip.sh
#! /bin/bash
Unix[0]='Debian'
Unix[1]='Red hat'
Unix[2]='Ubuntu'
Unix[3]='Suse'
echo ${Unix[1]}
$./arraymanip.sh
Red hat
배열의 특정 요소에 접근하려면 ${name[index]}처럼 중괄호를 사용합니다.
2. 선언과 동시에 배열 초기화하기
배열의 각 요소를 하나씩 초기화하는 대신, 괄호 안에 요소 목록(공백으로 구분)을 지정하여 배열을 선언하고 동시에 초기화할 수 있습니다.
문법: declare -a arrayname=(element1 element2 element3)
요소에 공백 문자가 포함되어 있다면 반드시 따옴표로 감싸야 합니다.
#! /bin/bash
$cat arraymanip.sh
declare -a Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora');
declare -a는 배열을 선언하며, 괄호 안의 모든 항목이 배열의 요소가 됩니다.
3. Bash 배열 전체 출력하기
배열의 모든 요소를 출력하는 방법은 여러 가지가 있습니다. 인덱스 자리에 @ 또는 *를 사용하면 배열의 모든 멤버를 참조하게 되며, Bash의 반복문을 활용해 배열 요소를 순회하며 출력할 수도 있습니다.
echo ${Unix[@]}
# 위 echo 문을 arraymanip.sh에 추가
#./t.sh
Debian Red hat Ubuntu Suse
인덱스 번호 없이 배열 변수를 참조하는 것은 인덱스 0번, 즉 첫 번째 요소를 참조하는 것과 동일합니다.
4. Bash 배열의 길이 구하기
${#arrayname[@]}를 사용하면 배열의 길이, 즉 요소 개수를 구할 수 있습니다.
$ cat arraymanip.sh
declare -a Unix=('Debian' 'Red hat' 'Suse' 'Fedora');
echo ${#Unix[@]} # 배열의 요소 개수
echo ${#Unix} # 배열 첫 번째 요소의 문자 수 (Debian)
$./arraymanip.sh
4
6
5. 배열에서 n번째 요소의 길이 구하기
${#arrayname[n]}를 사용하면 배열에서 n번째 요소의 길이를 구할 수 있습니다.
$cat arraymanip.sh
#! /bin/bash
Unix[0]='Debian'
Unix[1]='Red hat'
Unix[2]='Ubuntu'
Unix[3]='Suse'
echo ${#Unix[3]} # 인덱스 3에 위치한 요소(Suse)의 길이
$./arraymanip.sh
4
6. 오프셋과 길이로 배열 일부 추출하기
다음 예제는 Unix 배열에서 3번 위치부터 2개의 요소를 추출하는 방법을 보여줍니다.
$cat arraymanip.sh
Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux');
echo ${Unix[@]:3:2}
$./arraymanip.sh
Suse Fedora
위 예제는 인덱스 3번과 4번에 해당하는 요소를 반환합니다. 인덱스는 항상 0부터 시작한다는 점에 유의하세요.
7. 특정 요소에서 오프셋과 길이로 추출하기
배열의 특정 요소에서 일부 문자만 추출할 수도 있습니다. 예를 들어, 인덱스 2에 위치한 'Ubuntu'에서 처음 네 글자만 가져오려면 다음과 같이 오프셋과 길이를 지정합니다.
$cat arraymanip.sh
#! /bin/bash
Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux');
echo ${Unix[2]:0:4}
./arraymanip.sh
Ubun
위 예제는 배열에서 인덱스 2번 요소의 처음 네 문자를 추출합니다.
8. 배열 요소 검색 후 치환하기
다음 예제는 배열 요소 중에서 'Ubuntu'를 찾아 'SCO Unix'로 교체합니다.
$cat arraymanip.sh
#!/bin/bash
Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux');
echo ${Unix[@]/Ubuntu/SCO Unix}
$./arraymanip.sh
Debian Red hat SCO Unix Suse Fedora UTS OpenLinux
이 예제에서는 인덱스 2번의 요소인 'Ubuntu'가 'SCO Unix'로 대체되어 출력됩니다. 단, 이 방법은 배열의 원본 내용을 영구적으로 변경하지 않습니다.
9. 기존 Bash 배열에 요소 추가하기
다음 예제는 기존 배열에 새로운 요소를 추가하는 방법을 보여줍니다.
$cat arraymanip.sh
Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux');
Unix=("${Unix[@]}" "AIX" "HP-UX")
echo ${Unix[7]}
$./arraymanip.sh
AIX
Unix 배열에 'AIX'와 'HP-UX'가 각각 인덱스 7번과 8번에 추가됩니다.
10. 배열에서 요소 삭제하기
unset은 배열에서 요소를 제거하는 데 사용됩니다. unset은 해당 요소에 null을 할당하는 것과 같은 효과를 냅니다.
$cat arraymanip.sh
#!/bin/bash
Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux');
unset Unix[3]
echo ${Unix[3]}
위 스크립트는 인덱스 3번에 남아 있는 값, 즉 null만 출력합니다. 다음 예제는 배열에서 요소를 완전히 제거하는 방법 중 하나를 보여줍니다.
$ cat arraymanip.sh
Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux');
pos=3
Unix=(${Unix[@]:0:$pos} ${Unix[@]:$(($pos + 1))})
echo ${Unix[@]}
$./arraymanip.sh
Debian Red hat Ubuntu Fedora UTS OpenLinux
이 예제에서 ${Unix[@]:0:$pos}는 인덱스 0부터 3개의 요소(0, 1, 2)를 반환하고, ${Unix[@]:4}는 인덱스 4부터 마지막까지의 요소를 반환합니다. 두 결과를 병합하면 해당 요소가 제거된 새 배열이 만들어집니다. 이는 배열에서 요소를 제거하는 대표적인 우회 방법입니다.
11. 패턴을 사용해 배열 요소 삭제하기
검색 조건에 패턴을 지정하고, 패턴과 일치하지 않는 나머지 요소들을 다른 배열에 저장할 수 있습니다.
$ cat arraymanip.sh
#!/bin/bash
declare -a Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora');
declare -a patter=( ${Unix[@]/Red*/} )
echo ${patter[@]}
$ ./arraymanip.sh
Debian Ubuntu Suse Fedora
위 예제는 Red* 패턴과 일치하는 요소를 제거합니다.
12. 배열 복사하기
기존 배열의 요소를 확장(expansion)하여 새로운 배열에 저장하면 배열을 복사할 수 있습니다.
#!/bin/bash
Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux');
Linux=("${Unix[@]}")
echo ${Linux[@]}
$ ./arraymanip.sh
Debian Red hat Ubuntu Suse Fedora UTS OpenLinux
13. 두 Bash 배열 연결하기
두 배열의 요소를 확장하여 하나의 새로운 배열에 할당하면 됩니다.
$cat arraymanip.sh
#!/bin/bash
Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux');
Shell=('bash' 'csh' 'jsh' 'rsh' 'ksh' 'rc' 'tcsh');
UnixShell=("${Unix[@]}" "${Shell[@]}")
echo ${UnixShell[@]}
echo ${#UnixShell[@]}
$ ./arraymanip.sh
Debian Red hat Ubuntu Suse Fedora UTS OpenLinux bash csh jsh rsh ksh rc tcsh
14
'Unix'와 'Shell' 두 배열의 요소를 모두 포함하는 배열이 출력되며, 새 배열의 요소 개수는 14개입니다.
14. 배열 전체 삭제하기
unset을 사용하면 배열 전체를 삭제할 수 있습니다.
$cat arraymanip.sh
#!/bin/bash
Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux');
Shell=('bash' 'csh' 'jsh' 'rsh' 'ksh' 'rc' 'tcsh');
UnixShell=("${Unix[@]}" "${Shell[@]}")
unset UnixShell
echo ${#UnixShell[@]}
$ ./arraymanip.sh
0
배열을 unset하면 위 실행 결과처럼 배열의 길이가 0이 됩니다.
15. 파일 내용을 배열로 불러오기
파일의 내용을 한 줄씩 배열로 불러올 수 있습니다.
#Example file
$ cat logfile
Welcome
to
thegeekstuff
Linux
Unix
$ cat loadcontent.sh
#!/bin/bash
filecontent=( `cat "logfile" ` )
for t in "${filecontent[@]}"
do
echo $t
done
echo "Read file content!"
$ ./loadcontent.sh
Welcome
to
thegeekstuff
Linux
Unix
Read file content!
위 예제에서는 for 반복문을 통해 배열의 각 인덱스 요소가 차례대로 출력됩니다.
추천 도서
Ramesh Natarajan 저, 『Bash 101 Hacks』. 필자는 대부분의 시간을 Linux 환경에서 보내며, 그래서 자연스럽게 Bash 커맨드 라인과 셸 스크립팅의 열렬한 팬이 되었습니다. 15년 전 다양한 *nix 계열 시스템에서 작업할 때는 C 셸과 Korn 셸로 많은 코드를 작성했고, 이후 Linux 시스템 관리자로 일하면서 거의 모든 작업을 Bash 셸 스크립팅으로 자동화했습니다. 이러한 경험을 바탕으로 Bash 커맨드 라인과 셸 스크립팅에 관한 101가지 실용적인 예제를 담은 eBook 『Bash 101 Hacks』를 집필했습니다. Bash를 완벽히 마스터하고 싶다면 이 책을 읽어보세요. Bash 커맨드 라인과 셸 스크립팅을 자유자재로 다루는 데 큰 도움이 될 것입니다.