리눅스 seq 명령어 사용법 - 반복문 범위와 연속 이름 만들기
이 명령어를 언제 쓰는가
서버 10대에 같은 명령을 돌려야 할 때, 로그 파일을 01부터 12까지 월별로 만들 때, 테스트 데이터 1000줄이 필요할 때 seq를 쓴다. 하는 일은 단순하다. 시작값부터 끝값까지 한 줄에 하나씩 숫자를 찍는다.
단순하지만 셸 반복문의 재료로 워낙 자주 등장한다. 브레이스 확장({1..10})과 언제 무엇을 쓰는지, 자리수를 어떻게 맞추는지만 알아 두면 실무에서 필요한 건 거의 다 된다.
기본 형식
seq [옵션] 마지막
seq [옵션] 처음 마지막
seq [옵션] 처음 증감 마지막
- 인자 1개 — 1부터 그 값까지.
seq 5는 1 2 3 4 5. - 인자 2개 — 처음부터 마지막까지, 1씩 증가.
- 인자 3개 — 가운데가 증감폭이다. 음수를 주면 감소한다. 순서가
처음 증감 마지막이라는 점을 자주 헷갈린다.
자주 쓰는 옵션
| 옵션 | 의미 | 예시 |
|---|---|---|
-w | 0을 채워 자리수를 맞춘다 | seq -w 8 12 → 08 09 10 11 12 |
-s 문자 | 줄바꿈 대신 지정한 구분자로 잇는다 | seq -s, 1 5 → 1,2,3,4,5 |
-f 서식 | printf 서식으로 감싼다 | seq -f 'web%02g' 1 3 → web01 web02 web03 |
GNU seq의 옵션은 이 세 개가 사실상 전부다. BSD seq에는 종료 문자를 지정하는 -t가 더 있지만 리눅스에는 없다.
-f의 서식은 정수 서식(%d)이 아니라 실수 서식을 쓴다. %g, %f, %e만 허용되며 %d를 주면 오류가 난다. 자리수를 맞추려면 %02g처럼 쓴다.
실전 예제
1) 서버 목록을 만들어 일괄 점검한다. web01부터 web05까지 uptime을 확인하는 상황이다.
for h in $(seq -f 'web%02g' 1 5); do
echo "--- $h ---"
ssh -o ConnectTimeout=5 "$h" uptime
done
2) 월별 디렉터리를 자리수 맞춰 만든다. -w를 빼면 1과 10이 섞여 정렬이 흐트러진다.
for m in $(seq -w 1 12); do
mkdir -p "/data/archive/2026/$m"
done
3) 개수가 변수로 정해질 때 반복한다. 브레이스 확장은 변수를 못 쓰기 때문에 여기서는 seq가 답이다.
n=$(wc -l < /etc/hosts)
for i in $(seq 1 "$n"); do
sed -n "${i}p" /etc/hosts
done
4) 부하 테스트용 병렬 요청을 만든다. seq로 요청 번호를 만들고 xargs -P로 동시에 던진다.
seq 1 200 | xargs -P 20 -I{} \
curl -s -o /dev/null -w '{} %{http_code} %{time_total}\n' \
'http://127.0.0.1:8080/api/items?page={}'
5) 퍼센트 눈금이나 임계값 목록을 만든다. 증감폭을 주는 형태다.
seq -s' ' 0 10 100
0 10 20 30 40 50 60 70 80 90 100
6) 구분자로 이어 붙여 한 줄로 넘긴다. IN 절이나 CSV 헤더를 만들 때 쓴다.
seq -s, 1 5
1,2,3,4,5
함정과 주의점
GNU와 BSD가 역순에서 정반대로 동작한다. 리눅스(GNU coreutils)에서 seq 5 1은 아무것도 출력하지 않는다. 기본 증감이 +1인데 시작이 끝보다 크므로 조건이 성립하지 않기 때문이다. 그런데 macOS·FreeBSD의 BSD seq는 같은 명령에서 5 4 3 2 1을 찍는다. 알아서 방향을 뒤집는다. 맥에서 짠 스크립트가 리눅스 서버에서 반복문을 한 번도 안 돌고 조용히 넘어가는 사고가 여기서 나온다. 역순이 필요하면 어디서든 seq 5 -1 1로 증감폭을 명시한다.
-s의 마지막 구분자 처리도 다르다. GNU seq는 seq -s, 1 5가 1,2,3,4,5로 끝나지만, BSD seq는 마지막에도 구분자를 붙여 1,2,3,4,5,가 된다. SQL의 IN 절을 이렇게 만들면 문법 오류가 난다. 이식성이 필요하면 seq 1 5 | paste -sd, -를 쓰는 편이 안전하다.
큰 범위를 $(seq ...)로 감싸면 메모리를 통째로 쓴다. for i in $(seq 1 10000000)은 천만 개의 숫자를 문자열로 전부 메모리에 올린 뒤에야 반복을 시작한다. 수백 MB가 순식간에 날아간다. 큰 반복은 셸의 산술 for 문으로 바꾼다.
for ((i=1; i<=10000000; i++)); do
:
done
또는 seq 1 10000000 | while read -r i; do ... done처럼 파이프로 흘려보내면 메모리를 쓰지 않는다.
소수점 증감은 오차가 쌓인다. seq 0 0.1 1은 겉보기엔 깔끔하지만 내부적으로 부동소수 연산이라 범위가 넓어지면 마지막 값이 빠지거나 0.30000000000000004 같은 값이 나올 수 있다. 정밀도가 중요하면 정수로 만들고 나중에 나눈다.
고정된 작은 범위라면 브레이스 확장이 더 낫다. {1..10}은 셸 내부에서 처리돼 프로세스를 새로 띄우지 않는다. {01..12}로 자리수도 맞고 {0..100..10}으로 증감도 된다. 반대로 변수를 써야 하면 브레이스 확장은 못 쓴다. {1..$n}은 확장되지 않고 문자 그대로 {1..5}가 넘어간다. 이때가 seq를 쓰는 자리다.
함께 보면 좋은 명령어
- xargs — seq가 만든 목록을 병렬로 실행할 때 짝을 이룬다.
seq 1 100 | xargs -P 10 ... - awk — 서식이 복잡하거나 계산이 섞이면
awk 'BEGIN{for(i=1;i<=10;i++) printf("srv%02d\n", i)}'가 더 유연하다. - shuf — 순서가 아니라 무작위 표본이 필요하면
shuf -i 1-100 -n 10을 쓴다.