Skip to main content

7. 루프

대부분의 언어에는 루프라는 개념이 있습니다: 어떤 작업을 20번 반복하려면 매번 약간의 변경을 가하면서 코드를 20번 입력할 필요는 없습니다. 그 결과 본 셸에는 for 루프와 while 루프가 있습니다. 다른 언어에 비해 다소 적은 기능이지만, 셸 프로그래밍이 C의 힘을 가지고 있다고 주장하는 사람은 아무도 없습니다.

For 루프

"for" 루프는 목록이 모두 소진될 때까지 값 집합을 반복합니다:

#!/bin/sh
for i in 1 2 3 4 5
do
  echo "Looping ... number $i"
done

이 코드를 사용해 어떤 기능을 하는지 확인해 보세요. 값은 무엇이든 될 수 있다는 점에 유의하세요:

#!/bin/sh
for i in hello 1 * 2 goodbye
do
  echo "Looping ... i is set to $i"
done

시도해 볼 만한 가치가 있습니다. 여기서 무슨 일이 일어나고 있는지 이해했는지 확인하세요. "*" 없이 시도해 보고 아이디어를 파악한 다음 와일드카드 섹션을 다시 읽고 "*"를 제자리에 두고 다시 시도해 보세요. 다른 디렉토리에서도 "*"를 큰따옴표로 둘러싸고 그 앞에 백슬래시(\*)를 넣어 시도해 보세요.

현재 셸에 액세스할 수 없는 경우(이 튜토리얼을 읽는 동안 셸이 있으면 매우 유용합니다), 위의 두 스크립트의 결과는 다음과 같습니다:

Looping .... number 1
Looping .... number 2
Looping .... number 3
Looping .... number 4
Looping .... number 5

그리고 두 번째 예시에서는

Looping ... i is set to hello
Looping ... i is set to 1
Looping ... i is set to (name of first file in current directory)
... etc ...
Looping ... i is set to (name of last file in current directory) Looping ... i is set to 2
Looping ... i is set to goodbye

보시다시피, 주어진 입력이 무엇이든 입력이 다 떨어질 때까지 단순히 반복합니다.

 

While 루프

"while" 루프가 훨씬 더 재미있을 수 있습니다! (재미에 대한 여러분의 생각과 얼마나 자주 집을 나가느냐에 따라 다르겠지만... )

#!/bin/sh
INPUT_STRING=hello
while [ "$INPUT_STRING" != "bye" ]
do
   echo "Please type something in (bye to quit)" 
   read INPUT_STRING
   echo "You typed: $INPUT_STRING"
done

여기서 일어나는 일은 메시지가 표시될 때 "bye"를 입력할 때까지 에코 및 읽기 문이 무한정 실행된다는 것입니다. 테스트하기 전에 '변수 - 1부'(4장)를 검토하여 INPUT_STRING=hello를 설정한 이유를 알아보세요. 이렇게 하면 기존의 동안 루프가 아닌 반복 루프가 됩니다.

콜론(:)은 항상 참으로 평가됩니다. 콜론을 사용하는 것이 필요할 때도 있지만, 실제 종료 조건을 사용하는 것이 더 바람직할 때가 많습니다. 위의 루프를 종료하는 것과 아래의 루프를 종료하는 것을 비교하여 어느 것이 더 우아한지 살펴보세요. 또한 각각이 다른 것보다 더 유용할 수 있는 몇 가지 상황을 생각해 보세요:

#!/bin/sh
while :
do
   echo "Please type something in (^C to quit)" 
   read INPUT_STRING
   echo "You typed: $INPUT_STRING"
done

또 다른 유용한 트릭은 "while read" 루프입니다. 이 예제에서는 나중에 다룰 case 문을 사용합니다. 이 문은 파일 에서 읽고 각 줄에 대해 어떤 언어가 사용되고 있다고 생각하는지 알려줍니다.
(참고: 각 줄은 LF(개행)로 끝나야 합니다. cat myfile.txt가 빈 줄로 끝나지 않으면 마지막 줄은 처리되지 않습니다.).
이렇게 하면 "myfile.txt" 파일을 한 번에 한 줄씩 "$input_text" 변수로 읽습니다. 그런 다음 case 문은 $input_text의 값을 확인합니다. 읽은 단어가 "hello"인 경우 "English"라는 단어를 에코합니다. "gday"였다면 "Australian"가 echo로 출력됩니다. myfile.txt의 한 줄에서 읽은 단어가 제공된 패턴 중 어느 것과도 일치하지 않으면 포괄적인 "*" 기본값으로 "Unknown Language: $input_text"라는 메시지가 표시됩니다. 여기서 "$input_text"는 물론 myfile.txt에서 읽은 줄의 값입니다.

#!/bin/sh
while read input_text
do
  case $input_text in
        hello)                    echo English      ;;
        howdy)                    echo American     ;;
        gday)                     echo Australian   ;;
        bonjour)                  echo French       ;;
        "guten tag")              echo German
        *)                        echo Unknown Language: $input_text ;;
   esac
done < myfile.txt

"myfile.txt" 파일에 다음 다섯 줄이 포함되어 있다고 가정해 보겠습니다:

this file is called myfile.txt. It is an example text file. 
hello
gday
bonjour
hola

이 스크립트를 샘플로 실행하면 다음과 같습니다:

Unknown Language: this file is called myfile.txt. It is an example text file. 
English
Australian
French
Unknown Language: hola

리눅스 프롬 스크래치13 프로젝트에서 배운 편리한 Bash(본 셸은 아님) 팁은 다음과 같습니다:

mkdir rc{0,1,2,3,4,5,6,S}.d

대신에 더 번거로운 방법을 사용합니다:

for runlevel in 0 1 2 3 4 5 6 S
do
  mkdir rc${runlevel}.d
done

이 작업도 재귀적으로 수행할 수 있습니다:

$ cd /
$ ls -ld {,usr,usr/local}/{bin,sbin,lib}
drwxr-xr-x    2 root     root     4096 Oct 26 01:00 /bin
drwxr-xr-x    6 root     root     4096 Jan 16 17:09 /lib
drwxr-xr-x    2 root     root     4096 Oct 27 00:02 /sbin
drwxr-xr-x    2 root     root    40960 Jan 16 19:35 usr/bin 
drwxr-xr-x   83 root     root    49152 Jan 16 17:23 usr/lib
drwxr-xr-x    2 root     root     4096 Jan 16 22:22 usr/local/bin
drwxr-xr-x    3 root     root     4096 Jan 16 19:17 usr/local/lib  
drwxr-xr-x    2 root     root     4096 Dec 28 00:44 usr/local/sbin
drwxr-xr-x    2 root     root     8192 Dec 27 02:10 usr/sbin

Test 및 Case 장에서 while 루프에 대해 자세히 살펴보겠습니다.