iBetter Books
수정

for 루프

반복해야 할 대상이 명확할 때 for 루프를 씁니다. 파일 목록, 숫자 범위, 텍스트 파일의 항목들, 이 모두를 for 루프로 순회할 수 있습니다.

리스트 순회

가장 기본적인 형태입니다. 공백으로 구분된 항목들을 하나씩 꺼내 처리합니다.

for item in 사과 바나나 딸기; do    echo "과일: $item"done

실행 결과는 다음과 같습니다.

과일: 사과
과일: 바나나
과일: 딸기

범위 순회

{시작..끝} 형식으로 숫자 범위를 지정합니다.

# 1부터 5까지for i in {1..5}; do    echo "번호: $i"done# 1부터 10까지 2씩 증가 (홀수)for i in {1..10..2}; do    echo -n "$i "doneecho

실행 결과는 다음과 같습니다.

번호: 1
번호: 2
번호: 3
번호: 4
번호: 5
1 3 5 7 9

{시작..끝..증분} 형식으로 증분을 지정할 수 있습니다. 음수 증분으로 역순도 가능합니다. {10..1..-1}이면 10, 9, 8... 순으로 출력합니다.

C 스타일 for 루프

C 언어처럼 초기화, 조건, 증감식을 명시하는 방식입니다. 복잡한 반복 제어가 필요할 때 유용합니다.

for ((i=0; i<5; i++)); do    echo "i = $i"done# 짝수만 출력for ((i=0; i<=10; i+=2)); do    echo -n "$i "doneecho

실행 결과는 다음과 같습니다.

i = 0
i = 1
i = 2
i = 3
i = 4
0 2 4 6 8 10

(( )) 안에서는 $를 붙이지 않고 변수명을 바로 씁니다. PART 03의 산술 연산과 같은 규칙입니다.

글로빙으로 파일 순회

*를 이용해 특정 패턴에 맞는 파일들을 자동으로 목록으로 만들 수 있습니다.

# 현재 디렉토리의 모든 .txt 파일for file in *.txt; do    echo "처리 중: $file"done# 하위 디렉토리 포함for file in **/*.sh; do    echo "$file"done

주의할 점이 있습니다. 해당 패턴에 맞는 파일이 하나도 없으면 *.txt가 문자 그대로 $file에 들어갑니다. 안전하게 처리하려면 조건 검사를 추가합니다.

for file in *.txt; do    [[ -f "$file" ]] || continue    # 실제 파일이 아니면 건너뜀    echo "처리 중: $file"done

명령 치환으로 목록 만들기

명령의 출력 결과를 리스트로 사용할 수 있습니다.

# 파일에서 항목 읽기for user in $(cat /etc/passwd | cut -d: -f1); do    echo "사용자: $user"done# 명령 출력 결과 순회for pid in $(pgrep bash); do    echo "Bash PID: $pid"done

파일을 읽을 때 항목에 공백이 있다면 명령 치환 방식은 공백에서 잘릴 수 있습니다. 공백이 있는 행을 처리할 때는 while IFS= read -r을 사용하는 것이 더 안전합니다. 이 방법은 다음 절에서 다룹니다.

실습. 파일 일괄 이름 변경 스크립트

현재 디렉토리의 .txt 파일을 .bak 확장자로 복사하는 스크립트입니다.

#!/bin/bash# 새 파일: scripts/bulk_rename.shsource_ext="${1:-txt}"target_ext="${2:-bak}"count=0skipped=0echo "변환: .$source_ext → .$target_ext"echo "-----------------------------"for file in *."$source_ext"; do    if [[ ! -f "$file" ]]; then        echo "대상 파일이 없습니다 (*.${source_ext})"        exit 0    fi    newname="${file%.$source_ext}.$target_ext"    if [[ -f "$newname" ]]; then        echo "[SKIP] $file$newname (이미 존재)"        ((skipped++))        continue    fi    cp "$file" "$newname"    echo "[OK]   $file$newname"    ((count++))doneecho "-----------------------------"echo "완료: ${count}개 변환, ${skipped}개 건너뜀"

실행 결과는 다음과 같습니다.

$ touch note.txt report.txt readme.txt
$ bash scripts/bulk_rename.sh txt bak
변환: .txt → .bak
-----------------------------
[OK]   note.txt → note.bak
[OK]   readme.txt → readme.bak
[OK]   report.txt → report.bak
-----------------------------
완료: 3개 변환, 0개 건너뜀

$ bash scripts/bulk_rename.sh txt bak
변환: .txt → .bak
-----------------------------
[SKIP] note.txt → note.bak (이미 존재)
[SKIP] readme.txt → readme.bak (이미 존재)
[SKIP] report.txt → report.bak (이미 존재)
-----------------------------
완료: 0개 변환, 3개 건너뜀

${file%.$source_ext}는 파일명에서 확장자 부분을 제거하는 매개변수 확장입니다. %는 접미사를 제거합니다. 예를 들어 note.txt에서 .txt를 제거하면 note가 남습니다.

${1:-txt}는 첫 번째 인자가 없으면 txt를 기본값으로 사용하라는 의미입니다. 인자를 생략하면 .txt → .bak 변환이 기본 동작이 됩니다.