반복

반복 에서 Bash

{other: "%{count}개의 연습 문제"}

반복 소개

Bash에는 두 가지 루프 형식이 있어요:

  • 항목 목록의 각 항목마다 명령을 반복해요.
  • 어떤 조건이 참(또는 거짓)인 동안 명령을 반복해요.

for문

항목 목록을 순회하려면 for문을 사용해요.

for varname in words; do COMMANDS; done

words는 단어 분할과 파일명 확장을 통해 펼쳐져요(Quoting 개념에서 배운 내용이에요). 각 단어는 차례로 varname에 할당되고, COMMANDS가 실행돼요.

for문이 언제 유용한지 보여 주는 몇 가지 예시예요.

  • 여러 파일에 대해 명령을 실행해요.

    # source all the bash library files in the current directory
    for file in ./*.bash; do
        source "$file"
    done
    
  • 스크립트나 함수의 각 매개변수에 대해 명령을 실행해요.

    for arg in "$@"; do
        echo "argument: ${arg}"
    done
    
  • 어떤 명령의 출력에서 공백으로 구분된 각 단어마다 명령을 실행해요.

    for i in $(seq 10); do
        echo "${i} squared is $((i * i))"
    done
    

    이 방식에 대한 몇 가지 경고는 나중에 살펴볼 거예요.

산술 for문

Bash에는 산술 루프도 있어요. 다른 프로그래밍 언어를 써 본 사람이라면 어느 정도 익숙하게 보일 거예요.

for ((INITIALIZATION; CONDITION; INCREMENT)); do COMMANDS; done

Bash에서 이중 괄호는 산술 문맥을 나타내요(Bash 산술에 대해서는 나중 개념에서 더 살펴볼 거예요). 위의 seq를 사용한 예시는 이렇게 쓸 수 있어요.

for ((i = 1; i <= 10; i++)); do
    echo "${i} squared is $((i * i))"
done

for문을 쓰지 말아야 할 때

for로 줄을 읽지 마세요.

자주 보게 되는 안티 패턴이에요. cat의 출력을 순회하는 것이죠.

for line in $(cat some.file); do 
    do_something_with "$line"
done

이건 두 가지 면에서 잘못됐어요.

  1. 명령 치환이 따옴표로 감싸지지 않아서 단어 분할의 대상이 돼요. 단어 분할은 기본적으로 줄 바꿈뿐 아니라 공백 을 기준으로 나눠요. 이 for문은 파일의 줄이 아니라 파일의 단어 를 순회하고 있어요.
  2. 명령 치환이 따옴표로 감싸지지 않아서 파일명 확장의 대상이 돼요. 파일의 모든 단어가 글롭 패턴으로 매칭될 거예요.

Quoting 개념에서 배웠듯이, 단어 분할은 IFS 변수로 제어할 수 있고 파일명 확장은 끌 수 있어요. 하지만 이 방법은 깨지기 쉬운 해결책인 경우가 많아요. for는 파일의 줄을 순회하는 데 잘못된 방법이에요. 파일을 읽는 관용적인 방법은 while문을 사용하는 거예요.

while문

어떤 조건이 참인 동안 명령을 반복하려면 while을 사용해요.

while CONDITION_COMMANDS; do COMMANDS; done

if와 마찬가지로(Conditionals 개념에서 배웠듯이, CONDITION_COMMANDS에 특별한 문법은 없어요. 명령 목록의 종료 상태가 "true" 또는 "false"를 결정해요.

루프 제어

break 명령은 루프 밖으로 빠져나가요. 제어는 루프의 done 종결자 다음 명령부터 이어져요.

continue 명령은 루프의 다음 반복으로 건너뛰어요.

파일의 줄 읽기

앞서 말했듯이, 파일을 읽는 관용적인 방법은 while문이에요.

while IFS= read -r line; do
    do_something_with "$line"
done < some.file
  • 파일의 내용은 < 리다이렉션을 통해 루프의 입력으로 들어가요.

  • read 명령은 입력에서 한 줄 전체를 읽을 수 있으면 "true"를 반환해요. 입력이 다 소진되거나 마지막 줄이 줄 바꿈 없이 끝나면 read는 "false"를 반환해요.

    • 마지막 줄이 줄 바꿈으로 끝나지 않는 경우에도 파일의 줄을 읽는 진정으로 관용적인 방법은

      while IFS= read -r line || [[ -n "$line" ]]; do ...
      
  • -r 옵션은 read가 역슬래시 시퀀스를 치환하지 않도록 해요. 역슬래시는 그냥 평범한 문자예요.

  • IFS=는 read 명령이 실행되는 동안에만 IFS에 빈 문자열을 할당해요. 이렇게 하면 단어 분할이 일시적으로 꺼져서 들어오는 텍스트 줄의 앞뒤 공백이 그대로 유지돼요.

until문

until 구문은 어떤 조건이 거짓인 동안 명령을 반복해요. 루프는 조건이 참이 될 때까지 반복해요.

until CONDITION_COMMANDS; do COMMANDS; done

until을 사용하는 경우는 드물어요. "while not" 루프를 사용하는 경우가 더 흔해요.

while ! CONDITION_COMANDS; do ...

무한 루프

때로는 영원히 반복하고 싶을 때가 있어요. 두 가지 방법이 있어요.

  1. 항상 성공 종료 상태를 가지는 조건을 사용하는 while 루프

    while true; do ...
    
  2. 식이 비어 있는 산술 for 루프

    for ((;;)); do ...
    

Do-While

명시적인 do-while 구문은 없지만, 같은 효과를 낼 수 있어요:

while true; do
    COMMANDS

    if END_CONDITION; then
        break
    fi
done
GitHub에서 편집 링크가 새 창이나 탭에서 열려요