iBetter Books
수정

배열 순회와 조작

배열을 만들었으면 그 안의 값을 하나씩 처리해야 할 때가 많습니다. 전부 출력하거나, 조건에 맞는 것만 고르거나, 정렬하거나. 이번 절에서는 배열을 다루는 실용적인 기법들을 정리합니다.

for loop로 배열 순회

가장 기본적인 순회는 for ... in "${arr[@]}" 패턴입니다.

fruits=("apple" "banana" "cherry mango" "date")# 요소 순회 — "를 반드시 써야 공백 포함 요소 안전for fruit in "${fruits[@]}"; do    echo "과일: $fruit"done

출력 결과입니다.

과일: apple
과일: banana
과일: cherry mango
과일: date

"${fruits[@]}"에서 큰따옴표가 중요합니다. 따옴표 없이 ${fruits[@]}를 쓰면 "cherry mango"가 두 개의 인수로 쪼개집니다.

인덱스와 함께 순회하려면 C 스타일 for문을 씁니다.

fruits=("apple" "banana" "cherry")for (( i = 0; i < ${#fruits[@]}; i++ )); do    echo "[$i] ${fruits[$i]}"done

출력 결과입니다.

[0] apple
[1] banana
[2] cherry

연관 배열은 키 목록(${!assoc[@]})으로 순회합니다.

declare -A scoresscores["철수"]=85scores["영희"]=92scores["민수"]=78for name in "${!scores[@]}"; do    echo "$name: ${scores[$name]}점"done

배열 필터링

조건에 맞는 요소만 골라 새 배열을 만드는 패턴입니다.

numbers=(3 17 42 8 55 23 100 6 71 14)# 50 이상인 수만 필터링large=()for num in "${numbers[@]}"; do    if (( num >= 50 )); then        large+=("$num")    fidoneecho "원본: ${numbers[@]}"echo "50 이상: ${large[@]}"

출력 결과입니다.

원본: 3 17 42 8 55 23 100 6 71 14
50 이상: 55 100 71

문자열 배열에서 패턴으로 필터링하는 예입니다.

files=("report.txt" "image.png" "data.csv" "backup.txt" "graph.png")# .txt 파일만 골라내기txt_files=()for f in "${files[@]}"; do    if [[ "$f" == *.txt ]]; then        txt_files+=("$f")    fidoneecho "텍스트 파일: ${txt_files[@]}"

출력 결과입니다.

텍스트 파일: report.txt backup.txt

배열 정렬

Bash 배열 자체에는 정렬 기능이 없습니다. sort 명령어로 정렬한 결과를 readarray(또는 mapfile)로 배열에 담는 방법을 씁니다.

words=("banana" "apple" "cherry" "date" "elderberry")# 문자열 정렬readarray -t sorted < <(printf '%s\n' "${words[@]}" | sort)echo "정렬 전: ${words[@]}"echo "정렬 후: ${sorted[@]}"

출력 결과입니다.

정렬 전: banana apple cherry date elderberry
정렬 후: apple banana cherry date elderberry

숫자 정렬은 sort -n을 씁니다.

nums=(42 7 19 100 3 55)readarray -t sorted_nums < <(printf '%s\n' "${nums[@]}" | sort -n)echo "숫자 정렬: ${sorted_nums[@]}"# 역순readarray -t sorted_desc < <(printf '%s\n' "${nums[@]}" | sort -rn)echo "역순 정렬: ${sorted_desc[@]}"

출력 결과입니다.

숫자 정렬: 3 7 19 42 55 100
역순 정렬: 100 55 42 19 7 3

readarray -t는 줄 단위로 읽어서 배열에 담습니다. -t는 줄 끝의 개행문자를 제거합니다. < <(...)는 프로세스 치환으로, 명령어 출력을 마치 파일처럼 읽어옵니다.

배열을 함수 인수로 전달하는 방법

Bash에서 배열을 함수에 그대로 전달하는 방법은 두 가지입니다.

첫 번째는 배열 요소를 풀어서 전달하는 방법입니다. 함수 안에서는 $@으로 받습니다.

print_all() {    echo "인수 개수: $#"    for item in "$@"; do        echo "  - $item"    done}fruits=("apple" "banana" "cherry")print_all "${fruits[@]}"   # 배열 요소를 풀어서 전달

두 번째는 배열 이름을 전달하고 간접 참조를 쓰는 방법입니다. Bash 4.3+에서 declare -n(nameref)을 사용합니다.

sum_array() {    local -n arr=$1   # 배열 이름으로 참조    local total=0    for val in "${arr[@]}"; do        (( total += val ))    done    echo "$total"}nums=(10 20 30 40)result=$(sum_array nums)   # 배열 이름을 문자열로 전달echo "합계: $result"       # 합계: 100

local -n arr=$1arrnums 배열을 가리키는 참조(nameref)가 됩니다. 함수 안에서 arr을 쓰면 실제로는 nums를 조작합니다. 큰 배열을 복사 없이 함수에 전달할 때 유용합니다.

실습: 파일 목록 배열로 관리하기

#!/bin/bash# 새 파일: file_manager.sh# 현재 디렉토리의 파일 목록을 배열로 읽기readarray -t all_files < <(find . -maxdepth 1 -type f | sort)echo "=== 전체 파일 목록 ==="for (( i = 0; i < ${#all_files[@]}; i++ )); do    printf "  [%2d] %s\n" "$i" "${all_files[$i]}"doneecho "총 ${#all_files[@]}개"# 확장자별 필터링 함수filter_by_ext() {    local -n result=$1    # 결과 배열 (nameref)    local ext="$2"    result=()    for f in "${all_files[@]}"; do        if [[ "$f" == *."$ext" ]]; then            result+=("$f")        fi    done}echo ""echo "=== 확장자별 분류 ==="declare -a sh_filesdeclare -a md_filesfilter_by_ext sh_files "sh"filter_by_ext md_files "md"echo ".sh 파일 (${#sh_files[@]}개):"for f in "${sh_files[@]}"; do    echo "  $f"doneecho ".md 파일 (${#md_files[@]}개):"for f in "${md_files[@]}"; do    echo "  $f"done# 크기 기준 정렬 (가장 큰 파일 순)echo ""echo "=== 크기 기준 상위 5개 ==="readarray -t large_files < <(find . -maxdepth 1 -type f -printf "%s\t%f\n" | sort -rn | head -5)for entry in "${large_files[@]}"; do    size=$(echo "$entry" | cut -f1)    name=$(echo "$entry" | cut -f2)    printf "  %8d bytes  %s\n" "$size" "$name"done

readarray -t all_files < <(find ...) 패턴은 파일 목록처럼 외부 명령어 결과를 배열로 받을 때 자주 쓰입니다. filter_by_ext 함수는 nameref로 결과 배열을 직접 채워줍니다. 반환값으로 배열을 돌려주기 어려운 Bash에서 nameref가 좋은 대안이 됩니다.