강력한 루핑 전략: Bash 스크립트에서 파일 및 목록 반복 처리
Bash 루프는 쉘 스크립팅에서 자동화의 핵심입니다. 디렉터리의 모든 파일을 처리하거나, 특정 횟수만큼 작업을 수행하거나, 구성 데이터를 한 줄씩 읽어야 하는 경우, 루프는 반복적인 작업을 효율적으로 처리하는 데 필요한 구조를 제공합니다.
가장 기본적인 두 가지 Bash 루프 구조인 for와 while을 마스터하는 것은 강력하고 확장 가능하며 지능적인 스크립트를 작성하는 데 필수적입니다. 이 가이드에서는 목록, 파일, 디렉터리를 반복하고 시퀀스를 생성하여 자동화 워크플로우를 강화하기 위한 기본 구문, 실제 사용 사례 및 모범 사례를 살펴봅니다.
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. 흐름 제어: break 및 continue
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 스타일 루프를 사용합니다. |
결론
for 및 while 루프는 Bash 스크립팅의 기본이며, 코드 반복을 최소화하면서 복잡한 자동화 작업을 가능하게 합니다. 파일 처리를 위한 while IFS= read -r 접근 방식과 for 루프에서의 신중한 따옴표와 같은 강력한 패턴을 일관되게 적용하면 안정적이고 성능이 뛰어나며 예상치 못한 데이터 형식에 강한 스크립트를 구축할 수 있어 쉘 자동화 노력에 진정한 힘을 실어줄 수 있습니다.