조건

조건문 에서 Bash

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

조건문 소개

Bash에서의 참과 거짓

Bash에는 불리언 값이라는 개념이 없어요. 문자열과 숫자, 그리고 문자열이나 숫자의 배열만 있을 뿐이에요. 그렇다면 조건 명령은 참과 거짓을 어떻게 다룰까요?

종료 상태

명령은 끝날 때 _종료 상태_를 만들어요. 종료 상태는 0부터 255까지의 정수예요. Bash는 종료 상태가 0이면 _성공_을 나타낸다고 봐요. 그 밖의 종료 상태는 _실패_를 나타내요.

이것은 bash 내장 명령, 키워드, 함수를 포함한 모든 명령에 적용돼요.

if 명령

if 명령의 기본 문법은 다음과 같아요.

if CONDITIONAL_COMMANDS; then TRUE_COMMANDS; else FALSE_COMMANDS; fi

if로 시작하고, 조건 명령과 "성공" 명령은 then으로 구분하며, fi로 끝나요. else 절은 생략할 수 있어요.

CONDITIONAL_COMMANDS는 명령 하나일 수도 있고, 명령 목록일 수도 있어요.

CONDITIONAL_COMMANDS가 실행되고,

  • 종료 상태가 0(성공)이면 TRUE_COMMANDS가 실행돼요.
  • 종료 상태가 0이 아니면(실패) FALSE_COMMANDS가 있으면 실행돼요.

elif로 분기를 연달아 만들 수 있어요.

if CONDITIONAL_COMMANDS
then TRUE_COMMANDS
elif CONDITIONAL_COMMANDS_2
then TRUE_COMMANDS_2
# more elif branches ...
else FALSE_COMMANDS
fi

then, elif, else, fi 앞에는 세미콜론이나 줄바꿈이 있어야 해요.

다시 강조하면, 흐름을 결정하는 것은 조건 명령의 종료 상태예요. 예를 들어 grep은 일치하는 것을 찾으면 0을, 찾지 못하면 1을 반환해요. -q 옵션은 출력을 억제하고 종료 상태만 만들어요.

if grep -q "my pattern" my_file; then echo "the pattern is found in the file"; fi

[와 test 명령

CONDITIONAL_COMMANDS 주변에 특별한 문법은 없어요. 다음과 같은 if 문에 익숙할지도 몰라요:

if [ "$password" = "secure" ]; then
    echo "Welcome!"
fi

[는 특별한 문법이 아니에요. 조건식을 평가하고 성공/실패 상태로 종료하는 _명령_이에요. 모든 명령과 마찬가지로, 이것과 인자 사이에는 공백이 필요해요.

[는 사실 test 명령의 다른 이름이에요. [의 마지막 인자가 반드시 ]여야 한다는 점만 빼면 완전히 같아요.

조건식

[와 ] 안에는 조건식을 써요. 대표적인 조건식은 다음과 같아요:

[ -f "$filename" ]             # file operations
[ "$string1" = "$string2" ]    # string comparisons
[ "$num1" -eq "$num2" ]        # arithmetic comparisons

사용할 수 있는 연산은 훨씬 많아요. 매뉴얼의 Bash 조건식 절에 나와 있어요.

Note

위 예시에서 모든 변수가 따옴표로 묶여 있다는 점을 눈여겨봐요. test와 [ 명령은 평범한 명령이라, 인자가 다른 명령과 마찬가지로 단어 분할과 파일 이름 확장의 대상이 돼요.

조건식은 인자를 몇 개 주느냐에 따라 다르게 평가되기 때문에 이 점을 짚고 넘어가는 게 중요해요:

  • 인자 0개: 종료 상태가 0이 아니에요(실패).
  • 인자 1개: 인자가 비어 있지 않으면 종료 상태가 0(성공), 비어 있으면 0이 아니에요.
  • 인자 2개: 첫 번째 인자가 단항 연산자(예: [ -z "$name" ])이거나 !(1개 인자 검사의 상태를 부정)여야 해요.
  • 그리고 더 많은 경우가 있어요.

따옴표를 빠뜨리면 예상치 못한 결과가 나올 수 있어요:

str=""

# this prints "empty"
if [ -n "$str" ]; then echo "not empty"; else echo "empty"; fi

# leaving the variable unquoted results in incorrect "not empty" output
if [ -n $str ]; then echo "not empty"; else echo "empty"; fi

[[ 키워드

[[...]] 조건 구문은 _명령_이 아니라 키워드예요. 즉, 다른 명령처럼 다뤄지기는 하지만 특별한 파싱 규칙을 가져요. [[의 특별한 점은 그 안에서 확장되는 변수가 단어 분할이나 파일 이름 확장의 대상이 되지 않는다는 거예요. 그래서 따옴표를 쓰지 않아도 이 명령은 예상한 대로 동작해요.

if [[ -n $str ]]; then echo "not empty"; else echo "empty"; fi

[[는 test와 [가 다룰 수 있는 모든 조건식을 지원해요. 게다가 [[는 다음을 제공해요.

  • =~ 정규식 매칭 연산자,
  • 글롭 패턴 매칭 연산자로 동작하는 ==와 !=,
  • 논리 연산자로서의 &&와 || (특별한 파싱 규칙),
  • "그대로" 쓸 수 있는 문자열 비교 연산자로서의 <와 > (특별한 파싱 규칙: 이 기호들은 리다이렉션 기호라서 [ 안에서는 이스케이프해야 해요).

이런 특별한 기능들이 워낙 유용해서 [[만 써야 한다는 견해가 널리 퍼져 있어요. (예를 들어 Google 셸 스타일 가이드 같은 거예요.)

case 명령

case는 또 다른 제어 흐름 명령이에요. 다른 언어의 "switch" 문과 비슷해요.

case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac

WORD는 각 PATTERN과 대조돼요. 하나가 일치하면 COMMANDS가 실행돼요.

read -p "Guess the secret word: " word
case "$word" in
    secret) echo "Yes, you guessed it!" ;;
    ??????) echo "That's the right number of letters." ;;
    s*)     echo "You guessed the first letter." ;;
    *)      echo "Not even close! Try again." ;;
esac

각 COMMANDS 절은 세미콜론 두 개, ;;로 끝나야 해요.

Note
  1. 다음 절로 넘어가서 명령을 실행하는 기능과 패턴 매칭을 계속하는 기능을 제공하는 대안들도 있어요. 자세한 내용은 매뉴얼을 확인해 봐요.
  2. Quoting 개념의 파일 이름 확장 절에서 패턴에 대해 이야기했던 것을 떠올려 봐요.
GitHub에서 편집 링크가 새 창이나 탭에서 열려요