강력한 루핑 전략: Bash 스크립트에서 파일 및 목록 반복

`for`와 `while`을 사용하여 필수적인 Bash 루핑 기술을 마스터하여 반복적인 시스템 작업을 효율적으로 자동화하세요. 이 종합 가이드는 목록을 반복하고, 숫자 시퀀스를 처리하며, `while IFS= read -r`와 같은 모범 사례를 사용하여 파일을 한 줄씩 견고하게 처리하는 방법을 다룹니다. 기본 문법, 고급 루프 제어(`break`, `continue`)를 배우고, 강력하고 신뢰할 수 있는 셸 스크립팅 및 자동화를 위한 필수 기술을 실용적인 코드 예제와 함께 익히세요.

37 조회수

강력한 루핑 전략: Bash 스크립트에서 파일 및 목록 반복 처리

Bash 루프는 쉘 스크립팅에서 자동화의 핵심입니다. 디렉터리의 모든 파일을 처리하거나, 특정 횟수만큼 작업을 수행하거나, 구성 데이터를 한 줄씩 읽어야 하는 경우, 루프는 반복적인 작업을 효율적으로 처리하는 데 필요한 구조를 제공합니다.

가장 기본적인 두 가지 Bash 루프 구조인 forwhile을 마스터하는 것은 강력하고 확장 가능하며 지능적인 스크립트를 작성하는 데 필수적입니다. 이 가이드에서는 목록, 파일, 디렉터리를 반복하고 시퀀스를 생성하여 자동화 워크플로우를 강화하기 위한 기본 구문, 실제 사용 사례 및 모범 사례를 살펴봅니다.


for 루프: 고정된 집합 반복 처리

for 루프는 미리 처리해야 할 항목 집합을 알고 있을 때 이상적입니다. 이 집합은 명시적인 값 목록, 명령의 결과 또는 globbing을 통해 찾은 파일 집합이 될 수 있습니다.

1. 일반 목록 반복 처리

가장 일반적인 사용 사례는 공백으로 구분된 항목 목록을 반복하는 것입니다.

구문

for VARIABLE in LIST_OF_ITEMS; do
    # $VARIABLE을 사용하는 명령어
done

예제: 사용자 목록 처리

# 처리할 사용자 목록
USERS="alice bob charlie"

for user in $USERS; do
  echo "$user의 홈 디렉터리 확인 중..."
  if [ -d "/home/$user" ]; then
    echo "$user 님은 활성 상태입니다."
  else
    echo "경고: $user 홈 디렉터리가 누락되었습니다."
  fi
done

2. C 스타일 숫자 반복

개수 세기 또는 특정 숫자 시퀀스가 필요한 작업의 경우 Bash는 C 스타일 for 루프를 지원하며, 종종 중괄호 확장 또는 seq 명령과 함께 사용됩니다.

구문 (C 스타일)

for (( INITIALIZATION; CONDITION; INCREMENT )); do
    # 명령어
done

예제: 카운트다운 스크립트

# 5번 반복 (i는 1부터 시작하여 i가 5보다 작거나 같을 때까지 계속)
for (( i=1; i<=5; i++ )); do
  echo "반복 횟수: $i"
  sleep 1
done
echo "완료!"

대안: 중괄호 확장을 사용하여 간단한 시퀀스 생성

중괄호 확장은 연속 정수 또는 시퀀스를 생성하기 위해 seq를 사용하는 것보다 간단하고 빠릅니다.

# 10부터 1까지 숫자 생성
for num in {10..1}; do
  echo "카운트다운: $num"
done

3. 파일 및 디렉터리 반복 처리 (Globbing)

for 루프 내에서 와일드카드(*)를 사용하면 특정 패턴과 일치하는 파일(예: 모든 로그 파일 또는 디렉터리의 모든 스크립트)을 처리할 수 있습니다.

예제: 로그 파일 아카이빙

파일 이름, 특히 공백이나 특수 문자가 포함된 파일 이름을 다룰 때는 변수를 따옴표("$file")로 묶는 것이 중요합니다.

TARGET_DIR="/var/log/application"

# 대상 디렉터리에서 .log로 끝나는 모든 파일 반복
for logfile in "$TARGET_DIR"/*.log; do

  # 파일이 실제로 존재하는지 확인 (일치하는 파일이 없는 경우 리터럴 "*.log"에 대해 실행되지 않도록 방지)
  if [ -f "$logfile" ]; then
    echo "$logfile 압축 중..."
    gzip "$logfile"
  fi
done

while 루프: 조건 기반 실행

while 루프는 지정된 조건이 참인 동안 명령어 블록을 계속 실행합니다. 일반적으로 입력 스트림 읽기, 조건 모니터링 또는 반복 횟수를 알 수 없는 작업 처리에 사용됩니다.

1. 기본 while 루프

구문

while CONDITION; do
    # 명령어
done

예제: 리소스 대기

이 루프는 test 명령([ ])을 사용하여 진행하기 전에 디렉터리가 있는지 확인합니다.

RESOURCE_PATH="/mnt/data/share"

while [ ! -d "$RESOURCE_PATH" ]; do
  echo "리소스 $RESOURCE_PATH 마운트 대기 중..."
  sleep 5
done

echo "리소스 사용 가능. 백업 시작."

2. 강력한 while read 패턴

while 루프의 가장 강력한 적용은 파일 또는 출력 스트림의 내용을 한 줄씩 읽는 것입니다. 이 패턴은 cat 출력에 대한 for 루프를 사용하는 것보다 훨씬 뛰어나며, 공백과 특수 문자를 안정적으로 처리합니다.

모범 사례: 한 줄씩 읽기

최대한의 견고성을 보장하기 위해 세 가지 주요 구성 요소를 활용합니다.
1. IFS=: 내부 필드 구분 기호(Internal Field Separator)를 지워 전체 줄(선행/후행 공백 포함)이 변수로 읽히도록 합니다.
2. read -r: -r 옵션은 백슬래시 해석(원시 읽기)을 방지하여 경로 및 복잡한 문자열에 중요합니다.
3. 입력 리디렉션 (<): 파일 내용을 루프 안으로 리디렉션하여 루프가 현재 쉘 컨텍스트에서 실행되도록 합니다(하위 쉘 문제 방지).

# 데이터가 포함된 파일, 한 줄에 항목 하나
CONFIG_FILE="/etc/app/servers.txt"

while IFS= read -r server_name; do

  # 빈 줄 또는 주석 처리된 줄 건너뛰기
  if [[ -z "$server_name" || "$server_name" =~ ^# ]]; then
    continue
  fi

  echo "$server_name 서버 핑 중"
  ping -c 1 "$server_name"

done < "$CONFIG_FILE"

팁: 루프에서 cat 사용 피하기

파일을 읽을 때 cat file | while read line; do...를 절대 사용하지 마십시오. 파이핑은 하위 쉘을 생성하므로 루프 내에서 설정된 변수는 루프가 끝나면 손실됩니다. 대신 입력 리디렉션 패턴(while ... done < file)을 사용하십시오.

고급 루핑 제어 및 기법

효과적인 스크립트는 런타임 조건에 따라 루프 실행을 제어할 수 있어야 합니다.

1. 흐름 제어: breakcontinue

  • break: 남은 반복 횟수나 조건에 관계없이 즉시 전체 루프를 종료합니다.
  • continue: 현재 반복을 건너뛰고 즉시 다음 반복으로 이동합니다(또는 while 조건을 다시 평가합니다).

예제: 검색 및 중지

SEARCH_TARGET="target.conf"

for file in /etc/*; do
  if [ -f "$file" ] && [[ "$file" == *"$SEARCH_TARGET"* ]]; then
    echo "대상 구성 파일 발견 위치: $file"
    break  # 발견되면 처리 중지
  elif [ -d "$file" ]; then
    continue # 디렉터리는 건너뛰고 파일만 확인
  fi
  echo "파일 확인 중: $file"
done

2. IFS를 사용한 복잡한 구분 기호 처리

파일을 한 줄씩 읽으려면 IFS를 지워야 하지만, 다른 문자(예: 쉼표)로 구분된 목록을 반복하려면 IFS를 일시적으로 설정해야 합니다.

CSV_DATA="data1,data2,data3,data4"
OLD_IFS=$IFS # 원래 IFS 저장
IFS=','       # IFS를 쉼표 문자로 설정

for item in $CSV_DATA; do
  echo "항목 발견: $item"
done

IFS=$OLD_IFS # 루프 직후 원래 IFS 복원

경고: 전역 IFS 변경

스크립트 내에서 IFS를 수정하기 전에 항상 원래 $IFS를 저장하십시오(예: OLD_IFS=$IFS). 원래 값을 복원하지 않으면 후속 명령에서 예측할 수 없는 동작이 발생할 수 있습니다.

강력한 Bash 루프를 위한 모범 사례

모범 사례 근거
항상 변수를 따옴표로 묶으세요 단어 분할 및 glob 확장을 방지하기 위해 "$variable"을 사용합니다. 특히 파일 반복 시 중요합니다.
while IFS= read -r 사용 파일을 한 줄씩 처리하는 가장 안정적인 방법으로, 공백과 특수 문자를 올바르게 처리합니다.
존재 여부 확인 globbing(*.txt)을 사용할 때, 일치하는 파일이 없는 경우 루프가 리터럴 패턴 이름을 처리하지 않도록 항상 확인(if [ -f "$file" ];)을 포함하십시오.
변수 지역화 함수 내에서 local 키워드를 사용하여 루프 변수가 전역 변수를 실수로 덮어쓰는 것을 방지합니다.
외부 명령보다 내장 명령어 사용 성능을 위해 seq와 같은 외부 명령을 실행하는 대신 중괄호 확장({1..10}) 또는 C 스타일 루프를 사용합니다.

결론

forwhile 루프는 Bash 스크립팅의 기본이며, 코드 반복을 최소화하면서 복잡한 자동화 작업을 가능하게 합니다. 파일 처리를 위한 while IFS= read -r 접근 방식과 for 루프에서의 신중한 따옴표와 같은 강력한 패턴을 일관되게 적용하면 안정적이고 성능이 뛰어나며 예상치 못한 데이터 형식에 강한 스크립트를 구축할 수 있어 쉘 자동화 노력에 진정한 힘을 실어줄 수 있습니다.