루프 복합 명령 — for · while · until · select
이 글은 GNU Bash 매뉴얼 3.2.5.1 Looping Constructs에서 다루는 반복 구문을, 처음 배우는 분도 따라올 수 있게 쉬운 말로 풀어 정리합니다. “같은 일을 목록만큼 반복”하거나 “조건이 만족될 때까지 반복”하는 방법과, 반복을 중간에 빠져나오는 break / continue를 살펴봅니다.
이 글을 읽고 나면
for / while / until을 상황에 맞게 골라 쓸 수 있습니다.
C 스타일 for ((i=0; i<n; i++))로 숫자 반복을 작성할 수 있습니다.
break와 continue의 차이를 정확히 구분합니다.
무한 루프와 “공백에서 쪼개지는” 반복 사고를 피할 수 있습니다.
어떤 루프를 골라야 할까
반복문은 종류가 많아 보이지만, 고르는 기준은 “무엇을 반복할지” 하나입니다.
반복할 대상 |
알맞은 구문 |
한 줄 설명 |
|---|---|---|
정해진 목록 (파일들, 이름들) |
for |
항목 개수만큼 반복 |
조건이 참인 동안 |
while |
언제 끝날지 미리 모를 때 |
조건이 참이 될 때까지 |
until |
while의 반대 표현 |
숫자 카운터 (0부터 N까지) |
for ((…)) |
C 언어와 비슷한 형태 |
사용자에게 메뉴 선택 |
select |
번호를 붙인 메뉴 출력 |
Text
목록이 있다 ─────────▶ for 조건으로 돌린다 ──┬──▶ while (참인 동안 계속) └──▶ until (참이 될 때까지) 숫자를 센다 ─────────▶ for ((...)) 사람에게 고르게 한다 ─▶ select
for — 목록의 항목마다 한 번씩
가장 많이 쓰는 형태입니다. 목록을 앞에서부터 하나씩 꺼내 변수에 담고, 그 상태로 do ~ done 사이를 실행합니다.
Bash
for fruit in apple banana cherry; do echo "fruit=$fruit" done
동작을 그림으로 보면 이렇습니다.
Text
목록: apple banana cherry │ │ │ ▼ ▼ ▼ fruit= fruit= fruit= ← 매 회차마다 값이 바뀜 apple banana cherry │ │ │ └── do ~ done 실행 ──┘
항목에 공백이 있을 때
이전 글에서 본 “공백에서 단어가 쪼개지는” 문제가 여기서도 나옵니다. 파일 이름에 공백이 있으면, 한 항목이 두 개로 쪼개질 수 있습니다.
Bash
files=("report final.txt" "notes.md") # 배열로 목록을 만들고 for f in "${files[@]}"; do # 따옴표로 감싸 항목별로 꺼냄 echo "file=[$f]" done
목록을 생략하면
in ...을 아예 쓰지 않으면, 스크립트가 받은 인자들 을 반복합니다.
Bash
for arg; do # 'for arg in "$@"' 와 같은 뜻 echo "arg=$arg" done
while — 조건이 참인 동안 계속
몇 번 반복할지 미리 알 수 없을 때 씁니다. 조건을 검사해서 성공(참)이면 본문을 실행하고, 다시 조건으로 돌아갑니다.
Bash
count=1 while [ "$count" -le 3 ]; do echo "count=$count" count=$((count + 1)) # 이 줄이 없으면 영원히 반복됩니다 done
참고: -le, -gt 등 조건 연산자 모음
셸에서 숫자 비교 연산자는 아래와 같이 많이 쓰입니다.
연산자
의미
예시
-eq
equal (같다)
[ "$a" -eq "$b" ]
-ne
not equal (다르다)
[ "$a" -ne "$b" ]
-lt
less than (미만)
[ "$a" -lt "$b" ]
-le
less or equal (이하)
[ "$a" -le "$b" ]
-gt
greater than (초과)
[ "$a" -gt "$b" ]
-ge
greater or equal (이상)
[ "$a" -ge "$b" ]
위 예제의 -le는 "less than or equal to"(이하), 즉 "$count가 3 이하일 때" 반복한다는 뜻이에요.
Text
┌─────────────┐ ▼ │ 조건 검사 ──참──▶ 본문 실행 ──┘ │ 거짓 ▼ 종료
줄 단위로 읽기 (자주 쓰는 형태)
while은 “읽을 것이 남아 있는 동안” 반복할 때 특히 유용합니다.
Bash
printf 'line one\nline two\n' | while IFS= read -r line; do echo "read=[$line]" done
IFS= — 줄 앞뒤 공백을 없애지 않고 그대로 둡니다.
-r — 백슬래시(\)를 특수 문자로 해석하지 않습니다.
두 가지를 함께 쓰는 것이 안전한 관용구입니다.
until — 조건이 참이 될 때까지
while과 검사 방향만 반대입니다. 조건이 실패(거짓)인 동안 반복하고, 참이 되는 순간 멈춥니다.
Bash
n=1 until [ "$n" -gt 3 ]; do # n이 3보다 커지면 종료 echo "n=$n" n=$((n + 1)) done
구문 |
반복 조건 |
|---|---|
while 조건 |
조건이 참인 동안 계속 |
until 조건 |
조건이 거짓인 동안 계속 (참이 되면 종료) |
같은 일을 둘 다로 쓸 수 있지만, “~할 때까지 기다린다”는 뜻이면 until이 문장으로 더 자연스럽게 읽힙니다. 예를 들어 “서버가 응답할 때까지 재시도” 같은 상황입니다.
C 스타일 for — 숫자 반복에 편리
숫자를 세는 반복이라면 C 언어와 비슷한 형태가 읽기 좋습니다.
Bash
for ((i = 0; i < 3; i++)); do echo "i=$i" done
괄호 두 겹 안은 세 부분으로 나뉩니다.
위치 |
역할 |
예 |
|---|---|---|
첫 번째 |
시작할 때 한 번 실행 |
i = 0 |
두 번째 |
매 회차 전에 검사 |
i < 3 |
세 번째 |
매 회차 끝에 실행 |
i++ |
이 안에서는 $를 붙이지 않아도 변수를 쓸 수 있습니다. 숫자 계산 전용 구역이기 때문입니다.
select — 번호 메뉴 만들기
사용자에게 목록을 보여 주고 번호로 고르게 할 때 씁니다. 형태는 for와 거의 같습니다.
Bash
select fname in a.txt b.txt; do echo "you picked $fname (번호: $REPLY)" break # 고르면 한 번만 처리하고 종료 done
화면에 번호가 붙은 목록이 나오고, 입력 프롬프트가 뜹니다.
고른 값은 변수(fname)에, 입력한 번호는 REPLY에 담깁니다.
break가 없으면 계속 다시 묻습니다.
break와 continue — 반복 흐름 바꾸기
명령 |
하는 일 |
|---|---|
continue |
이번 회차의 남은 부분만 건너뛰고 다음 회차로 |
break |
반복문 자체를 즉시 종료 |
Bash
for num in 1 2 3 4 5; do if [ "$num" -eq 2 ]; then continue # 2는 건너뜀 → 아래 echo 실행 안 함 fi if [ "$num" -eq 4 ]; then break # 4에서 반복 종료 → 5는 아예 안 봄 fi echo "num=$num" done # 출력: num=1, num=3
중첩된 반복문에서는 숫자를 붙여 몇 겹을 빠져나갈지 정할 수 있습니다. break 2는 바깥 반복문까지 두 겹을 종료합니다.
실행 예제
아래 스크립트는 지금까지 본 반복 구문을 한 화면에서 비교해 보여 줍니다.
Bash
#!/usr/bin/env bash # for / while / until / C 스타일 for / break / continue 를 한 화면에서 비교합니다. set -eu echo "=== 1) for: 목록의 각 항목을 한 번씩 ===" for fruit in apple banana cherry; do # (1) 목록을 하나씩 fruit 에 담아 반복 echo "fruit=$fruit" done echo echo "=== 2) for: 공백이 있는 항목도 안전하게 ===" files=("report final.txt" "notes.md") # (2) 배열로 목록을 만듦 for f in "${files[@]}"; do # (3) "${배열[@]}" → 항목별로 하나씩 echo "file=[$f]" done echo echo "=== 3) while: 조건이 참인 동안 반복 ===" count=1 while [ "$count" -le 3 ]; do # (4) count 가 3 이하인 동안 반복 echo "count=$count" count=$((count + 1)) # (5) 조건을 바꿔야 끝남 (무한 루프 방지) done echo echo "=== 4) until: 조건이 참이 될 때까지 반복 ===" n=1 until [ "$n" -gt 3 ]; do # (6) n 이 3 보다 커질 때까지 반복 echo "n=$n" n=$((n + 1)) done echo echo "=== 5) C 스타일 for: 숫자 카운터에 편리 ===" for ((i = 0; i < 3; i++)); do # (7) 초기값; 조건; 증가 echo "i=$i" done echo echo "=== 6) break / continue ===" for num in 1 2 3 4 5; do if [ "$num" -eq 2 ]; then continue # (8) 이번 회차만 건너뛰고 다음으로 fi if [ "$num" -eq 4 ]; then break # (9) 반복 자체를 즉시 종료 fi echo "num=$num" done echo echo "=== 7) while read: 줄 단위로 읽기 ===" printf 'line one\nline two\n' | while IFS= read -r line; do # (10) 한 줄씩 안전하게 echo "read=[$line]" done echo echo "ok — 반복 구문은 '무엇을 반복할지'에 따라 골라 씁니다."
주요 라인별 설명
1: 목록의 항목을 하나씩 변수에 담아 반복합니다. 가장 기본 형태입니다.
2–3: 공백이 있는 항목은 배열 + "${배열[@]}" 조합으로 안전하게 꺼냅니다.
4–5: while은 조건이 참인 동안 반복합니다. 5번 줄이 없으면 무한 루프가 됩니다.
6: until은 조건이 참이 되는 순간 멈춥니다. while과 방향이 반대입니다.
7: C 스타일 for는 “시작·조건·증가” 세 부분으로 숫자를 셉니다.
8–9: continue는 이번 회차만 건너뛰고, break는 반복 자체를 끝냅니다.
10: IFS= read -r는 줄 내용을 있는 그대로 읽는 안전한 관용구입니다.
실행하면 대략 이런 결과가 나옵니다.
Text
=== 1) for: 목록의 각 항목을 한 번씩 === fruit=apple fruit=banana fruit=cherry === 2) for: 공백이 있는 항목도 안전하게 === file=[report final.txt] file=[notes.md] === 3) while: 조건이 참인 동안 반복 === count=1 count=2 count=3 === 4) until: 조건이 참이 될 때까지 반복 === n=1 n=2 n=3 === 5) C 스타일 for: 숫자 카운터에 편리 === i=0 i=1 i=2 === 6) break / continue === num=1 num=3 === 7) while read: 줄 단위로 읽기 === read=[line one] read=[line two]
break/continue 부분에서 2는 건너뛰어 출력되지 않고, 4에서 반복이 끝나 5는 아예 나오지 않는다는 점을 확인할 수 있습니다.
헷갈리기 쉬운 부분
무한 루프 — while/until 본문에서 조건에 쓰인 값이 변하지 않으면 영원히 돌아갑니다. 값이 바뀌는 줄이 있는지 먼저 확인하세요.
목록이 공백에서 쪼개짐 — for f in $files처럼 따옴표 없이 쓰면 파일 이름의 공백에서 항목이 갈라집니다. 배열과 "${배열[@]}"를 쓰세요.
while과 until을 반대로 사용 — “~인 동안”은 while, “~가 될 때까지”는 until입니다. 조건식을 그대로 두고 구문만 바꾸면 동작이 뒤집힙니다.
파이프 뒤의 while에서 변수가 안 남음 — cmd | while ... 형태는 별도 프로세스에서 돌아, 루프 안에서 바꾼 변수가 루프 밖에 남지 않을 수 있습니다. (해결 방법은 이후 글에서 다룹니다.)
select에 break를 안 넣음 — 계속 다시 묻습니다. 한 번만 고르게 하려면 본문 끝에 break가 필요합니다.
한 줄 요약
목록이 있으면 for, 조건으로 돌리면 while(참인 동안) 또는 until(참이 될 때까지), 숫자를 세면 for ((…))를 쓰고, 흐름은 continue(이번 회차만 건너뜀)와 break(반복 종료)로 조절합니다.