Test Operators

이 연산자들은 test, [ builtin 명령에서 제공하는 것으로 [[ ]] 에서도 동일하게 사용할 수 있습니다.
( 단 -a, -o 연산자는 제외. [[ ]] 에서는 자체 && , || 연산자를 제공합니다.)

File Tests

파일이 실행파일인지 테스트할 때 사용하는 -x 이나 -r, -w 연산자는 파일의 drwxrwxr-x 모드 값을 가지고 판단합니다. 그러므로 디렉토리도 테스트에 성공할 수 있습니다. 디렉토리를 제외하고 실행 파일인지 테스트하려면 다음과 같이 합니다.

$ if [ -f "$file" -a -x "$file" ]; then ... fi

연산자는 test -fx "$file" 와 같이 두 개를 붙여 쓰기 할 수 없습니다.

test 되는 파일이 symbolic link 일경우 -L, -h 연산자는 링크 자체를 테스트하고 나머지는 링크에 연결된 대상 파일을 테스트합니다.

연산자 설명
-a <FILE> 파일이 존재하면 true 입니다.
( Logical AND 연산자와 구분이 어려우므로 사용하지 않는 것을 권장. )
-e <FILE> 파일이 존재하면 true 입니다.
-f <FILE> 파일이 존재하고 regular 파일이면 true 입니다.
-d <FILE> 파일이 존재하고 directory 이면 true 입니다.
-c <FILE> 파일이 존재하고 character special 파일이면 true 입니다.
(터미널도 character special 에 해당)
-b <FILE> 파일이 존재하고 block special 파일이면 true 입니다.
-p <FILE> 파일이 존재하고 (named, unnamed) pipe 이면 true 입니다.
-S <FILE> 파일이 존재하고 socket 이면 true 입니다.
-L <FILE> 파일이 존재하고 symbolic link 이면 true 입니다.
-h <FILE> 파일이 존재하고 symbolic link 이면 true 입니다.
-g <FILE> 파일이 존재하고 sgid bit 이 설정돼 있으면 true 입니다.
-u <FILE> 파일이 존재하고 suid bit 이 설정돼 있으면 true 입니다.
-k <FILE> 파일이 존재하고 sticky bit 이 설정돼 있으면 true 입니다.
-r <FILE> 파일이 존재하고 readable 이면 true 입니다.
-w <FILE> 파일이 존재하고 writable 이면 true 입니다.
-x <FILE> 파일이 존재하고 executable 이면 true 입니다.
-O <FILE> 파일이 존재하고 uid (user id) 가 같으면 true 입니다.
-G <FILE> 파일이 존재하고 gid (group id) 가 같으면 true 입니다.
-N <FILE> 파일이 존재하고 마지막에 read 한뒤로 modify 되었으면 true 입니다.
-s <FILE> 파일이 존재하고 사이즈가 0 보다 크면 (not empty) true 입니다.
-t <fd> FD 가 존재하고 현재 터미널에 연결돼 있으면 true 입니다.
<FILE1> -nt <FILE2> FILE1 이 FILE2 보다 수정시간이 newer 면 true 입니다.
<FILE1> -ot <FILE2> FILE1 이 FILE2 보다 수정시간이 older 면 true 입니다.
<FILE1> -ef <FILE2> FILE1 과 FILE2 가 서로 hardlink 되어 있으면 true 입니다.

String Tests

보통 프로그래밍 언어에서 < , > 는 숫자를 비교할때 사용되는데 shell 에서는 특이하게 스트링을 비교하는데 사용됩니다. 생각 같아서는 스트링 연산자와 산술연산자가 서로 바뀌었으면 헷갈리지 않고 좋을것 같은데 사실 이것도 알고보면 shell 스트립트가 갖는 근본적인 한계입니다. 왜냐하면 shell 에서는 <= , >= 와 같은 연산자를 사용하기 어렵습니다. 이렇게 사용하게 되면 = 가 파일명이 되고 < , > 가 redirection 기호가 되기 때문입니다.

예를 들어 expr 명령은 산술연산을 하는 명령인데 연산자를 사용할 때는 모두 \< \<= \> =\> \& \| \* 와 같이 escape 해야 합니다.

< , > 연산자는 사전적으로 (lexicographically) 비교하기 때문에 숫자를 비교하는데 사용하면 안됩니다 (100 보다 2 가 크다고 나옵니다). 또한 shell redirection 메타문자와 충돌하므로 사용할땐 escape 해야 합니다.

연산자 설명
-z <STRING> 스트링이 empty 면 true 입니다.
( 변수가 존재하지 않는 경우에도 해당됩니다. )
-n <STRING> 스트링이 empty 가 아니면 true 입니다.
<STRING1> = <STRING2> 두 스트링 값이 같으면 true 입니다.
<STRING1> != <STRING2> 두 스트링 값이 다르면 true 입니다.
<STRING1> < <STRING2> 사전적으로 비교했을 때 스트링1 이 작으면 true 입니다.
( 사용할땐 escape 합니다. )
<STRING1> > <STRING2> 사전적으로 비교했을 때 스트링1 이 크면 true 입니다.
( 사용할땐 escape 합니다. )

참고로 변수값이 empty 인지 테스트할 때 아래와 같이 작성하는 경우가 있습니다. 이것은 옛날 버전의 test 명령이 변수값이 -a, -n 같은 옵션 문자일 경우 제대로 처리하지 못하기 때문이라고 합니다.

$ if [ x"$var" = x ]; then ...

# $var 값이 -a 이라면 [ -a = "" ] 가 되어 옛날 버전의 test 명령에서 오류 발생
$ if [ "$var" = "" ]; then ...

# 다음과 같이 작성하면 [ x-a = x ] 가 되므로 문제가 생기지 않는다.
$ if [ x"$var" = x ]; then ...

Arithmetic Tests

test 명령의 산술 연산자는 기본적으로 정수만 다룹니다.

연산자 설명
<INTEGER1> -eq <INTEGER2> 두 수가 같으면 true 입니다.
<INTEGER1> -ne <INTEGER2> 두 수가 같지 않으면 true 입니다.
<INTEGER1> -le <INTEGER2> INT1 이 INT2 보다 작거나, 두 수가 같으면 true 입니다.
<INTEGER1> -ge <INTEGER2> INT1 이 INT2 보다 크거나, 두 수가 같으면 true 입니다.
<INTEGER1> -lt <INTEGER2> INT1 이 INT2 보다 작으면 true 입니다.
<INTEGER1> -gt <INTEGER2> INT1 이 INT2 보다 크면 true 입니다.

비교가 참일 경우 종료 상태 값으로 0 을, 거짓이면 1 을 반환하고 그 외 비교 값이 정수가 아니거나 오류가 발생하면 2 를 반환합니다. 따라서 다음과 같은 방법으로 입력값이 정수인지 판단할 수 있습니다.

num=123a

test "$num" -eq 0 2> /dev/null;

if [ $? -lt 2 ]; then
    echo "It's integer"
else
    echo "It's not integer"
fi

Misc Syntax

연산자 설명
<TEST1> -a <TEST2> 두 테스트 간에 AND 연산을 할 때 사용합니다.
-a 연산자는 파일 테스트에서도 사용되므로 주의해야 합니다.
<TEST1> -o <TEST2> 두 테스트 간에 OR 연산을 할 때 사용합니다.
! <TEST> Logical NOT 연산을 합니다.
( <TEST> ) 우선순위 조절을 위해 사용할 수 있습니다
( 사용할땐 escape 합니다. )
-o <OPTION_NAME> set builtin 명령으로 설정하는 옵션의 현재 값을 테스트할 때 사용합니다.
현재 -o 상태면 true, +o 상태면 false 입니다.
-v <VARIABLENAME> 변수가 존재하는지 테스트할 때 사용합니다.
존재하지 않는 상태 (unset 상태) 면 1 을, 그 외에는 0 을 리턴합니다.
-R <VARIABLENAME> 변수가 named reference 이면 true 입니다. (bash version 4.3+).

Quiz

파일이 바이너리 파일인지 아닌지는 어떻게 구분할까요?

if [ -f "$filename" -a "$(file -b --mime-encoding "$filename")" = binary ]
then
    echo It\'s a binary file
fi

test, expr 명령은 기본적으로 정수값만 다루는데요. 쉘에서 float 값을 비교하려면 어떻게 할까요?

$ val1=12.1 val2=5.28

# bc 명령은 표현식이 참일때 1 을 출력합니다.
$ if [ 1 = $( echo "$val1 > $val2" | bc ) ]; then echo "Y"; fi
Y

$ if [ 1 = $( echo "$val1 < $val2" | bc ) ]; then echo "Y"; fi
$

$ res=$( echo "$val1 + $val2" | bc ); echo $res
17.38

$ bc <<< 'scale=1000; 1 / 998001' 
.0000010020030040050060070080090100110120130140150160170180190200210\
22023024025026027028029030031032033034035036037038039040041042043044\
04504604704804905005105205305405505605705805906006106206306406506606\
70680690700710720730740750760770780790800810820830840850860870880890\
......