if/then 은 명령어 목록의 종료 상태가 0 (유닉스 관례상 0은 "성공"을 나타내므로)인지 테스트를 해보고 맞다면 다음 명령어들을 실행시킵니다.
테스트 전용 명령어로 [ (왼쪽 대괄호 특수 문자)란 것이 있습니다. test 명령어와 동의어이고, 효율적인 이유로 내장 명령입니다. 이 명령어는 자신의 인자를 비교식이나 파일 테스트로 인식해 해당 연산의 결과에 따른 종료 상태(참은 0, 거짓은 1)를 리턴합니다.
또한, 다른 언어를 쓰던 프로그래머에게 어느 정도 더 친숙한 비교 연산을 제공해 주는 [[ ... ]]를 Bash 2.02 버전부터 제공합니다. 주의할 점은 [[가 명령어가 아닌 키워드라는 것입니다.
Bash 는 [[ $a -lt $b ]] 를 종료 상태를 리턴하는 하나의 요소로 이해합니다.
(( ... )) 와 let ... 은 자신이 계산한 산술식이 0이 아닌 값을 가질 경우에 종료 상태 0을 리턴합니다. 따라서, 이런 산술 확장은 산술 비교를 할 때 쓸 수 있습니다.
let "1<2" 는 0 을 리턴("1<2" 가 "1" 로 확장되므로) (( 0 && 1 )) 은 1 을 리턴("0 && 1" 이 "0" 으로 확장되므로) |
if 는 대괄호로 조건을 묶지 않고도 아무 명령어나 테스트 할 수 있습니다.
if cmp a b > /dev/null # 결과를 무시. then echo "파일 a 와 b 는 같습니다." else echo "파일 a 와 b 는 다릅니다." fi if grep -q Bash file then echo "file에는 Bash가 적어도 한 번 이상 나옵니다." fi if 에러가_없을_때_종료_상태가_0인_명령어 then echo "성공." else echo "실패." fi |
if/then 은 중첩된 비교나 테스트가 가능합니다.
if echo "다음에 나오는 *if* 는 첫번째 *if* 의 비교 대상에 포함됩니다." if [[ $comparison = "integer" ]] then (( a < b )) else [[ $a < $b ]] fi then echo '$a 는 $b 보다 적습니다.' fi |
이 자세한 "if-test" 확장 예제들은 Stephane Chazelas가 제공해 주었습니다.
예 7-1. 무엇이 참인가?
#!/bin/bash echo echo "\"0\" 테스트" if [ 0 ] # zero then echo "0 은 참." else echo "0 은 거짓." fi echo echo "\"NULL\" 테스트" if [ ] # NULL (empty condition) then echo "NULL 은 참." else echo "NULL 은 거짓." fi echo echo "\"xyz\" 테스트" if [ xyz ] # 문자열 then echo "임의의 문자열은 참." else echo "임의의 문자열은 거짓." fi echo echo "\"\$xyz\" 테스트" if [ $xyz ] # $xyz 가 널인지 테스트... # 하지만 단지 초기화되지 않은 변수일 때만. then echo "초기화 안 된 변수는 참." else echo "초기화 안 된 변수는 거짓." fi echo echo "\"-n \$xyz\" 테스트" if [ -n "$xyz" ] # 좀 더 어렵게 보이게. then echo "초기화 안 된 변수는 참." else echo "초기화 안 된 변수는 거짓." fi echo xyz= # 널 값으로 초기화. echo "\"-n \$xyz\" 테스트" if [ -n "$xyz" ] then echo "널 변수는 참." else echo "널 변수는 거짓." fi echo # "false"가 참일 때. echo "\"false\" 테스트" if [ "false" ] # "false"는 그냥 문자열 같죠? then echo "\"false\" 는 참." #+ 그래서 참이 되네요. else echo "\"false\" 는 거짓." fi echo echo "\"\$false\" 테스트" # 초기화 안 된 변수, 다시. if [ "$false" ] then echo "\"\$false\" 는 참." else echo "\"\$false\" 는 거짓." fi # 흠, 이게 우리가 원하던 거죠. echo exit 0 |
연습문제. 위에 나온 예 7-1의 동작을 설명해 보세요.
if [ condition-true ] then command 1 command 2 ... else # 옵션(필요 없다면 빠져도 됩니다). # 원래 조건이 실패했을 경우 동작할 코드들을 두세요. command 3 command 4 ... fi |
'if'와 'then'을 같은 줄에 두려면 세미콜론을 쓰세요.
if [ -x "$filename" ]; then |
elif는 else if의 단축형입니다. 바깥쪽 if/then의 안쪽에 중첩해서 쓰는 효과를 가져옵니다.
if [ condition1 ] then command1 command2 command3 elif [ condition2 ] # else if 와 같습니다. then command4 command5 else default-command fi |
if test condition-true와 if [ condition-true ] 은 완전히 똑같은 표현입니다. [ 는 test 명령어를 부르는 토큰이기 때문에 ] 가 꼭 필요하진 않지만 새 버전의 bash 에서는 그래도 있어야 됩니다.
참고: test 명령어는 파일 타입을 테스트하거나 문자열을 비교해 주는 bash 내장 명령이기 때문에, Bash 스크립트안에서 test는 sh-utils 패키지의 일부분인 /usr/bin/test 외부 명령어를 부르지 않습니다. 비슷하게, [도 /usr/bin/test로 링크되어 있는 /usr/bin/[를 부르지 않습니다.
bash$ type test test is a shell builtin bash$ type '[' [ is a shell builtin bash$ type '[[' [[ is a shell keyword bash$ type ']]' ]] is a shell keyword bash$ type ']' bash: type: ]: not found
예 7-2. [ ] 와 test 의 동일함
#!/bin/bash echo if test -z "$1" then echo "명령어줄 인자가 없습니다." else echo "첫번째 명령어줄 인자는 $1 입니다." fi if [ -z "$1" ] # 위의 코드 블럭과 기능적으로 동일합니다. # if [ -z "$1" 라고 해도 동작하겠지만... #+ Bash 는 오른쪽 대괄호가 빠졌다고 에러 메세지를 냅니다. then echo "명령어줄 인자가 없습니다." else echo "첫번째 명령어줄 인자는 $1 입니다." fi echo exit 0 |
[[ ]] 는 쉘 상에서 [ ]과 동일합니다. 이 명령어는 ksh88에서 따 온 확장 테스트 명령어입니다.
참고: [[ 과 ]] 사이에서는 파일명 확장이나 낱말 조각남이 일어나지 않지만 매개변수 확장이나 명령어 치환은 일어납니다.
file=/etc/passwd if [[ -e $file ]] then echo "비밀번호 파일이 존재합니다." fi |
작은 정보: [ ... ] 말고 [[ ... ]] 를 쓰면 많은 논리적 에러들을 막을 수 있습니다. 예를 들어 &&, ||, <, > 연산자들은 [ ] 에서 에러를 내지만 [[ ]] 에서는 잘 동작합니다.
참고: if다음에 꼭 test나 테스트 대괄호( [ ]나 [[ ]] )가 나오지 않아도 됩니다.
"if COMMAND" 문은 COMMAND의 종료 상태를 리턴합니다.
dir=/home/bozo if cd "$dir" 2>/dev/null; then # "2>/dev/null" 는 에러 메세지를 숨겨줍니다. echo "현재 디렉토리는 $dir 입니다." else echo "$dir 로 옮겨갈 수 없습니다." fi비슷하게, 테스트 대괄호가 리스트와 같이 쓰이면 if 없이 단독으로 쓰일 수도 있습니다.
var1=20 var2=22 [ "$var1" -ne "$var2" ] && echo "$var1 는 $var2 와 같지 않습니다." home=/home/bozo [ -d "$home" ] || echo "$home 디렉토리는 존재하지 않는 디렉토리입니다."
(( )) 문은 산술식을 평가해서 확장해 줍니다. 그 산술식이 0 으로 평가되면 종료 상태 1이나 "false"를 리턴하고 0 이 아닌 값으로 평가되면 종료 상태 0이나 "true"를 리턴합니다. 앞에서 얘기했던 test나 [ ]와 현격한 차이를 보여줍니다.