7.3. 비교 연산자(이진)

정수 비교

-eq

같음

if [ "$a" -eq "$b" ]

-ne

같지 않음

if [ "$a" -ne "$b" ]

-gt

더 큼

if ["$a" -gt "$b" ]

-ge

더 크거나 같음

if [ "$a" -ge "$b" ]

-lt

더 작음

if [ "$a" -lt "$b" ]

-le

더 작거나 같음

if [ "$a" -le "$b" ]

<

더 작음(이중 소괄호에서)

(("$a" < "$b"))

<=

더 작거나 같음(이중 소괄호에서)

(("$a" <= "$b"))

>

더 큼(이중 소괄호에서)

(("$a" > "$b"))

>=

더 크거나 같음(이중 소괄호에서)

(("$a" >= "$b"))

문자열 비교

=

같음

if [ "$a" = "$b" ]

==

같음

if [ "$a" == "$b" ]

= 와 동의어입니다.

[[ $a == z* ]]    # $a 가 "z"로 시작하면 참(패턴 매칭)
[[ $a == "z*" ]]  # $a 가 z* 와 같다면 참

[ $a == z* ]      # 파일 globbing이나 낱말 조각남이 일어남
[ "$a" == "z*" ]  # $a 가 z* 와 같다면 참

# Thanks, S.C.

!=

같지 않음

if [ "$a" != "$b" ]

이 연산자는 [[ ... ]] 에서 패턴 매칭을 사용합니다.

<

아스키 알파벳 순서에서 더 작음

if [[ "$a" < "$b" ]]

if [ "$a" \< "$b" ]

"<"[ ] 에서 쓰일 때는 이스케이프를 시켜야 하는 것에 주의하세요.

>

아스키 알파벳 순서에서 더 큼

if [[ "$a" > "$b" ]]

if [ "$a" \> "$b" ]

">"[ ] 에서 쓰일 때는 이스케이프를 시켜야 하는 것에 주의하세요.

이 비교 연산자를 어떻게 응용하는지 예 26-4에서 살펴보세요.

-z

문자열이 "null"임. 즉, 길이가 0

-n

문자열이 "null"이 아님.

경고

테스트 대괄호에서 -n 테스트를 받는 문자열은 꼭 쿼우트 시켜야 됩니다. 쿼우트 안 된 문자열을 ! -z와 같이 쓰거나 테스트 대괄호 없이 단독(예 7-5 참고)으로 쓰면 보통은 동작하겠지만, 위험한 습관입니다. 테스트문에서 쓰이는 문자열은 항상 쿼우트를 시켜 주세요. [1]

예 7-4. 산술 비교와 문자열 비교

#!/bin/bash

a=4
b=5

#  여기서 "a"와 "b"는 정수나 문자열 양쪽 모두로 해석될 수 있습니다.
#  Bash 변수는 타입에 대해 관대하기 때문에
#+ 산술 비교와 문자열 비교에는 약간 애매한 부분이 있습니다.

#  Bash 는 숫자로만 이루어진 변수에 대해서 
#+ 산술 비교도 허용하고 문자열 비교도 허용합니다.
#  주의해서 쓰기 바랍니다.

if [ "$a" -ne "$b" ]
then
  echo "$a 와 $b 는 같지 않습니다."
  echo "(산술 비교)"
fi

echo

if [ "$a" != "$b" ]
then
  echo "$a 는 $b 와 같지 않습니다."
  echo "(문자열 비교)"
fi

# 여기서 "-ne" 와 "!=" 는 둘 다 동작합니다.

echo

exit 0

예 7-5. 문자열이 인지 테스트 하기

#!/bin/bash
# str-test.sh: Testing null strings and unquoted strings,
# but not strings and sealing wax, not to mention cabbages and kings...
# (옮긴이: ??? :)

# if [ ... ]  를 쓸께요.


#  문자열이 초기화 안 됐다면 정해진 값을 갖지 않는데
#+ 이런 상태를 "널"(null)이라고 부릅니다(0 과는 다릅니다).

if [ -n $string1 ]    # $string1 은 선언도 초기화도 안 됐습니다.
then
  echo "\"string1\" 은 널이 아닙니다."
else  
  echo "String \"string1\" 은 널입니다."
fi  
# 틀렸죠.
# 초기화가 안 됐는데도 널이 아닌 것으로 나오네요.


echo


# 다시 해보죠.

if [ -n "$string1" ]  # 이번엔 $string1 을 쿼우트 시켜서 해보죠.
then
  echo "\"string1\" 은 널이 아닙니다."
else  
  echo "\"string1\" 은 널입니다."
fi      # 테스트문에서는 문자열을 꼭 쿼우트 시키세요!


echo


if [ $string1 ]       # 이번엔 달랑 $string1 만 두고 해보죠.
then
  echo "\"string1\" 은 널이 아닙니다."
else  
  echo "\"string1\" 은 널입니다."
fi  
# 이건 잘 되네요.
# 문자열을 쿼우트 시키는 게("$string1") 좋은 습관이긴 하지만
# [ ] 테스트 연산자는 혼자 쓰이면 문자열이 널인지 아닌지를 잘 알아냅니다.
#
# Stephane Chazelas 가 지적한 것처럼,
#    if [ $string 1 ]   는 인자가 "]" 하나고,
#    if [ "$string 1" ]  는 인자가 빈 "$string1"과 "]", 두 개입니다.



echo



string1=initialized

if [ $string1 ]       # , $string1 을 다시 혼자 써보죠.
then
  echo "\"string1\" 은 널이 아닙니다."
else  
  echo "\"string1\" 은 널입니다."
fi  
# 역시 결과가 맞게 잘 나오죠.
# 마찬가지로 이유로 쿼우트 해주는 것이("$string1") 좋습니다. 왜냐하면...


string1="a = b"

if [ $string1 ]       # $string1 을 또 혼자 씁니다.
then
  echo "\"string1\" 은 널이 아닙니다."
else  
  echo "\"string1\" 은 널입니다."
fi  
# 이제 "$string1"을 쿼우트 해 주지 않으면 틀린 결과가 나옵니다!

exit 0
# Florian Wisser가 날카롭게 지적해 준 것에도 감사합니다.

예 7-6. zmost

#!/bin/bash

# 'most'로 gzip으로 묶인 파일을 보기

NOARGS=65
NOTFOUND=66
NOTGZIP=67

if [ $# -eq 0 ] # if [ -z "$1" ] 라고 해도 같음
# $1 이 존재하지만 비어 있을 수 있습니다:  zmost "" arg2 arg3
then
  echo "사용법: `basename $0` filename" >&2
  # 표준에러로 에러 메세지를 출력.
  exit $NOARGS
  # 스크립트의 종료 코드(에러 코드)로 65를 리턴.
fi  

filename=$1

if [ ! -f "$filename" ]   # $filename 에 빈 칸이 들어 있을 수도 있기 때문에 쿼우팅해줍니다.
then
  echo "$filename 파일을 찾을 수 없습니다!" >&2
  # 표준출력으로 에러 메세지를 출력.
  exit $NOTFOUND
fi  

if [ ${filename##*.} != "gz" ]
# 변수 치환인 중괄호를 사용함.
then
  echo "$1 파일은 gzip 파일이 아닙니다!"
  exit $NOTGZIP
fi  

zcat $1 | most

# 'most' 파일 뷰어 쓰기('less'와 비슷).
# 'more'나 'less'로 바꿔도 괜찮음.


exit $?   # 파이프의 종료 상태를 리턴.
#  스크립트는 어떤 경우든지간에 마지막에 실행된 명령어의 종료 상태를 
#+ 리턴하기 때문에 실제로는 "exit $?"가 필요없습니다.

복합 비교

-a

논리 and

exp1 -a exp2 는 exp1 과 exp2 모두 참일 경우에만 참을 리턴합니다.

-o

논리 or

exp1 -o exp2 는 exp1 이나 exp2 중 하나라도 참일 경우에 참을 리턴합니다.

이것들은 이중 대괄호에서 쓰이는 Bash 비교 연산자인 &&||와 비슷합니다.
[[ condition1 && condition2 ]]
-o-a 연산자는 test 명령어나 테스트 대괄호안에서 동작합니다.
if [ "$exp1" -a "$exp2" ]

복합 비교 연산자가 실제로 쓰이는 예는 예 8-2예 26-7를 참고.

주석

[1]

S.C. 가 지적한대로 복합 테스트에서는 쿼우팅만으로 충분치 않을 수도 있습니다. [ -n "$string" -o "$a" = "$b" ]의 경우 $string이 비어 있을 경우, 몇몇 Bash 버전에서는 에러를 낼 수도 있습니다. 안전하게 가려면 비어 있는 값을 가질 가능성이 있는 변수에 글자를 덧붙여 주면 됩니다. [ "x$string" != x -o "x$a" = "x$b" ]("x's"는 모두 상쇄됩니다).