Bash의 for 루프는 크게 두 가지 방식으로 작성할 수 있습니다. 하나는 "in" 키워드와 함께 값 목록을 사용하는 방식이며, 다른 하나는 C 프로그래밍 언어와 유사한 문법을 사용하는 방식입니다.
이 글은 지속적으로 연재되고 있는 Bash 튜토리얼 시리즈의 일부입니다. 두 가지 for 루프 방식을 모두 설명하고, 셸 스크립트에서 for 루프를 활용할 수 있는 12가지 서로 다른 예제를 소개합니다.
Bash for 루프 활용법이 궁금할 때 이 글 하나면 충분하니, 나중에 다시 찾아볼 수 있도록 북마크해 두시기 바랍니다.
방법 1: "in" 키워드와 값 목록을 사용하는 Bash For 루프
기본 문법은 다음과 같습니다.
for varname in list do command1 command2 .. done
위 문법에서 각 요소는 다음과 같은 의미를 가집니다.
- for, in, do, done은 모두 예약어(키워드)입니다.
- "list"는 값 목록을 의미하며, 공백으로 구분된 여러 단어를 담고 있는 변수일 수도 있습니다. 만약 for 문에서 목록을 생략하면, 셸 스크립트로 전달된 위치 매개변수(positional parameters)가 자동으로 사용됩니다.
- varname은 임의의 Bash 변수 이름입니다.
이 형식에서 for 문은 목록의 각 항목마다 본문에 포함된 명령들을 한 번씩 실행합니다. 예를 들어 목록에 값이 5개 있다면 for 루프는 총 5번 실행되며, 루프가 돌 때마다 현재 항목이 변수 "varname"에 저장됩니다. 이 변수는 for 루프 본문 안에서 자유롭게 가공할 수 있습니다.
방법 2: C 언어 스타일 문법을 사용하는 Bash For 루프
두 번째 형식의 for 루프는 C 프로그래밍 언어의 for 루프와 비슷하며, 초기화(initialization), 조건(condition), 증감(updation)이라는 세 개의 표현식으로 구성됩니다.
for (( expr1; expr2; expr3 )) do command1 command2 .. done
위 Bash for 명령 문법의 동작 방식은 다음과 같습니다.
- 첫 번째 반복이 시작되기 전에 expr1이 평가됩니다. 주로 루프에서 사용할 변수를 초기화하는 용도로 쓰입니다.
- do와 done 사이의 모든 명령문은 expr2가 참(TRUE)인 동안 반복해서 실행됩니다.
- 루프가 한 번 돌 때마다 expr3이 평가됩니다. 주로 카운터 값을 증가시키는 용도로 사용됩니다.
이제 아래 12가지 예제를 통해 Bash for 루프를 다양하게 활용하는 방법을 살펴보겠습니다.
1. "in" 키워드 뒤에 정적 값 목록 지정하기
다음 예제에서는 값 목록(Mon, Tue, Wed, Thu, Fri)을 for 루프의 "in" 키워드 바로 뒤에 직접 나열합니다.
$ cat for1.sh i=1 for day in Mon Tue Wed Thu Fri do echo "Weekday $((i++)) : $day" done $ ./for1.sh Weekday 1 : Mon Weekday 2 : Tue Weekday 3 : Wed Weekday 4 : Thu Weekday 5 : Fri
주의: 값 목록은 쉼표(,)로 구분하면 안 됩니다. Mon, Tue, Wed처럼 쉼표를 넣으면 쉼표까지 값의 일부로 인식되어, "Mon" 대신 "Mon,"이 값으로 사용됩니다. 아래 예제를 보면 잘못된 결과가 출력되는 것을 확인할 수 있습니다.
$ cat for1-wrong1.sh i=1 for day in Mon, Tue, Wed, Thu, Fri do echo "Weekday $((i++)) : $day" done $ ./for1-wrong1.sh Weekday 1 : Mon, Weekday 2 : Tue, Weekday 3 : Wed, Weekday 4 : Thu, Weekday 5 : Fri,
주의: 값 목록 전체를 큰따옴표로 묶어서도 안 됩니다. ("Mon Tue Wed Thu Fri") 큰따옴표로 묶으면 5개의 개별 값이 아니라 하나의 값으로 취급되어, 아래 예제처럼 루프가 한 번만 실행됩니다.
$ cat for1-wrong2.sh i=1 for day in "Mon Tue Wed Thu Fri" do echo "Weekday $((i++)) : $day" done $ ./for1-wrong2.sh Weekday 1 : Mon Tue Wed Thu Fri
2. "in" 키워드 뒤에 변수 사용하기
값을 for 루프에 직접 나열하는 대신, 변수에 저장해 두고 "in" 키워드 뒤에서 해당 변수를 사용할 수도 있습니다. 아래 예제를 참고하세요.
$ cat for2.sh i=1 weekdays="Mon Tue Wed Thu Fri" for day in $weekdays do echo "Weekday $((i++)) : $day" done $ ./for2.sh Weekday 1 : Mon Weekday 2 : Tue Weekday 3 : Wed Weekday 4 : Thu Weekday 5 : Fri
주의: 일반적으로 Bash 변수를 참조할 때는 따옴표로 감싸는 것이 좋은 습관입니다. 하지만 몇 가지 예외가 있으며, 그중 하나가 바로 이 경우입니다. for 루프에서 변수를 큰따옴표로 감싸면 값 목록 전체가 하나의 값으로 취급됩니다. 많은 초보자가 이 함정에 빠지므로, for 루프에서는 변수에 큰따옴표를 붙이지 않도록 주의해야 합니다.
$ cat for2-wrong.sh i=1 weekdays="Mon Tue Wed Thu Fri" for day in "$weekdays" do echo "Weekday $((i++)) : $day" done $ ./for2-wrong.sh Weekday 1 : Mon Tue Wed Thu Fri
3. 목록을 생략하고 위치 매개변수에서 값 가져오기
Bash for 루프에서 "in" 키워드와 값 목록을 생략하면, 위치 매개변수(즉, 셸 스크립트에 전달된 인자들)가 자동으로 목록으로 사용됩니다.
$ cat for3.sh i=1 for day do echo "Weekday $((i++)) : $day" done $ ./for3.sh Mon Tue Wed Thu Fri Weekday 1 : Mon Weekday 2 : Tue Weekday 3 : Wed Weekday 4 : Thu Weekday 5 : Fri
주의: 이 방법을 사용할 때는 조심해야 합니다. "in" 키워드만 적고 값 없이 남겨두면 위치 매개변수가 사용되지 않습니다. 아래 예제처럼 루프 본문이 전혀 실행되지 않으며, for 루프 자체가 동작하지 않게 됩니다.
$ cat for3-wrong.sh i=1 for day in do echo "Weekday $((i++)) : $day" done $ ./for3-wrong.sh Mon Tue Wed Thu Fri
참고: Bash 위치 매개변수에 대한 더 자세한 내용은 관련 문서나 이전 아티클을 참고하시기 바랍니다.
4. "in" 키워드 뒤에 유닉스 명령어 출력 결과 사용하기
역따옴표(back-tick) ` ` 로 명령어를 감싸면, UNIX/Linux 명령어의 출력 결과를 for 루프의 값 목록으로 사용할 수 있습니다. 아래 예제를 확인해 보세요.
$ cat for4.sh
i=1
for username in `awk -F: '{print $1}' /etc/passwd`
do
echo "Username $((i++)) : $username"
done
$ ./for4.sh
Username 1 : ramesh
Username 2 : john
Username 3 : preeti
Username 4 : jason
..
5. 파일과 디렉터리를 순회하는 For 루프
특정 디렉터리 아래의 파일과 디렉터리를 순회하려면 해당 디렉터리로 cd한 후, for 루프에서 *를 지정하기만 하면 됩니다. 아래 예제는 홈 디렉터리 아래의 모든 파일과 디렉터리를 순회합니다.
$ cat for5.sh i=1 cd ~ for item in * do echo "Item $((i++)) : $item" done $ ./for5.sh Item 1 : positional-parameters.sh Item 2 : backup.sh Item 3 : emp-report.awk Item 4 : item-list.sed Item 5 : employee.db Item 8 : storage Item 9 : downloads
Bash for 루프에서 *를 사용하는 것은 리눅스 명령줄에서 ls 명령어(및 기타 명령어)를 사용할 때 적용되는 파일 글로빙(globbing)과 같은 개념입니다.
예를 들어, 다음 명령은 홈 디렉터리 아래의 모든 파일과 디렉터리를 표시합니다. 위의 for5.sh 예제에서 사용된 것이 바로 이 개념입니다.
cd ~ ls *
다음 명령은 /etc 디렉터리 아래에서 a, b, c, d로 시작하는 *.conf 파일을 모두 표시합니다.
$ ls -1 /etc/[abcd]*.conf /etc/asound.conf /etc/autofs_ldap_auth.conf /etc/cas.conf /etc/cgconfig.conf /etc/cgrules.conf /etc/dracut.conf
위 ls 명령어에서 사용한 것과 동일한 패턴 인자를 Bash for 루프에서도 그대로 사용할 수 있습니다. 아래 예제를 참고하세요.
$ cat for5-1.sh i=1 for file in /etc/[abcd]*.conf do echo "File $((i++)) : $file" done $ ./for5-1.sh File 1 : /etc/asound.conf File 2 : /etc/autofs_ldap_auth.conf File 3 : /etc/cas.conf File 4 : /etc/cgconfig.conf File 5 : /etc/cgrules.conf File 6 : /etc/dracut.conf
6. break로 For 루프 빠져나오기
break 명령을 사용하면 특정 조건에서 for 루프를 강제로 종료할 수 있습니다. 아래 예제를 확인해 보세요.
$ cat for6.sh i=1 for day in Mon Tue Wed Thu Fri do echo "Weekday $((i++)) : $day" if [ $i -eq 3 ]; then break; fi done $ ./for6.sh Weekday 1 : Mon Weekday 2 : Tue
7. continue로 루프 상단부터 계속 진행하기
continue 명령을 사용하면 특정 조건에서 for 루프의 나머지 명령들을 건너뛰고, 루프 상단부터 다시 실행할 수 있습니다(목록의 다음 값으로 넘어감). 아래 예제는 Sat과 Sun에는 "(WEEKEND)"를, 나머지 요일에는 "(weekday)"를 추가합니다.
$ cat for7.sh i=1 for day in Mon Tue Wed Thu Fri Sat Sun do echo -n "Day $((i++)) : $day" if [ $i -eq 7 -o $i -eq 8 ]; then echo " (WEEKEND)" continue; fi echo " (weekday)" done $ ./for7.sh Day 1 : Mon (weekday) Day 2 : Tue (weekday) Day 3 : Wed (weekday) Day 4 : Thu (weekday) Day 5 : Fri (weekday) Day 6 : Sat (WEEKEND) Day 7 : Sun (WEEKEND)
8. C 프로그램 스타일 문법으로 For 루프 사용하기
이 예제는 C 언어의 for 루프 문법과 유사한 두 번째 방식을 사용합니다. 아래 예제는 Bash의 C 스타일 for 루프를 이용해 난수 5개를 생성합니다.
$ cat for8.sh for (( i=1; i <= 5; i++ )) do echo "Random number $i: $RANDOM" done $ ./for8.sh Random number 1: 23320 Random number 2: 5070 Random number 3: 15202 Random number 4: 23861 Random number 5: 23435
9. 무한 For 루프 만들기
Bash의 C 스타일 for 루프에서 초기값, 조건, 증감값을 모두 생략하면 무한 루프가 됩니다. 루프를 멈추려면 Ctrl-C를 눌러야 합니다.
$ cat for9.sh i=1; for (( ; ; )) do sleep $i echo "Number: $((i++))" done
앞서 말했듯이, 이 무한 for 루프 예제를 빠져나오려면 Ctrl-C를 누르면 됩니다.
$ ./for9.sh Number: 1 Number: 2 Number: 3
10. C 스타일 For 루프에서 쉼표 활용하기
Bash의 C 스타일 루프에서는 조건에 사용되는 값 외에 다른 값도 함께 증가시킬 수 있습니다. 초기화 영역과 증감 영역에서 쉼표로 구분하여 여러 값을 지정할 수 있습니다.
아래 for 루프는 변수 i를 기준으로 총 5번 실행됩니다. 그런데 변수 j는 5에서 시작하여 루프가 실행될 때마다 5씩 증가합니다.
$ cat for10.sh for ((i=1, j=10; i <= 5 ; i++, j=j+5)) do echo "Number $i: $j" done $ ./for10.sh Number 1: 10 Number 2: 15 Number 3: 20 Number 4: 25 Number 5: 30
11. "in" 키워드 뒤에 숫자 범위 지정하기
for 루프의 "in" 키워드 뒤에서 중괄호 확장(brace expansion)을 사용하면 숫자 범위를 손쉽게 순회할 수 있습니다.
아래 예제는 1부터 10까지의 값을 이용해 총 10번 루프를 실행합니다.
$ cat for11.sh
for num in {1..10}
do
echo "Number: $num"
done
$ ./for11.sh
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
...
12. 증가폭을 포함한 숫자 범위 지정하기
다음 예제는 1부터 10까지의 값을 증가폭 2로 사용해 5번 루프를 실행합니다. 즉, 1에서 시작하여 2씩 증가하다가 10에 도달하면 종료됩니다.
$ cat for12.sh
for num in {1..10..2}
do
echo "Number: $num"
done
$ ./for12.sh
Number: 1
Number: 3
Number: 5
Number: 7
Number: 9
PS: 나중에 다시 참고하실 수 있도록 이 글을 북마크해 두는 것을 잊지 마세요.