摘要本章我們會討論在Bash腳本中使用條件,包含以下幾個話題: if 語句 使用命令的退出狀態(tài)比較和測試輸入和文件 if/then/else
結(jié)構 if/then/elif/else 結(jié)構 使用和測試位置參數(shù)嵌套 if 語句 布爾表達式使用 case 語句
7.1. 介紹if
7.1.1. 概要 有時候你需要指定shell腳本中的依靠命令的成功與否來實施不同過程的行為。if 結(jié)構允許你來指定這樣的條件。 最精簡的 if 命令的語法是:
if
TEST-COMMANDS; then CONSEQUENT-COMMANDS; fi TEST-COMMAND
執(zhí)行后且它的返回狀態(tài)是0,那么 CONSEQUENT-COMMANDS 就執(zhí)行。返回狀態(tài)是最后一個命令的退出狀態(tài),或者當沒有條件是真的話為0。
TEST-COMMAND
經(jīng)常包括數(shù)字和字符串的比較測試,但是也可以是任何在成功時返回狀態(tài)0或者失敗時返回一些其他狀態(tài)的一些命令。一元表達式經(jīng)常用于檢查文件的狀態(tài)。如果對
某個要素primaries, FILE 參數(shù)是 /dev/fd/N 這樣的形式,那么就檢查文件描述符 “N”。stdin, stdout 和
stderr 和他們各自的文件描述符也可以用于測試。
7.1.1.1. 和if使用的表達式 下表包含了一個組成 TEST-COMMAND 命令或者命令列表,稱作 “要素primaries” 的概覽。這些primaries放置在方括號中來表示一個條件表達式的測試。 表 7.1. 主表達式Primary 意義
[ -a FILE ] 如果 FILE 存在則為真。
[ -b FILE ] 如果 FILE 存在且是一個塊特殊文件則為真。
[ -c FILE ] 如果 FILE 存在且是一個字特殊文件則為真。
[ -d FILE ] 如果 FILE 存在且是一個目錄則為真。
[ -e FILE ] 如果 FILE 存在則為真。
[ -f FILE ] 如果 FILE 存在且是一個普通文件則為真。
[ -g FILE ] 如果 FILE 存在且已經(jīng)設置了SGID則為真。
[ -h FILE ] 如果 FILE 存在且是一個符號連接則為真。
[ -k FILE ] 如果 FILE 存在且已經(jīng)設置了粘制位則為真。
[ -p FILE ] 如果 FILE 存在且是一個名字管道(F如果O)則為真。
[ -r FILE ] 如果 FILE 存在且是可讀的則為真。
[ -s FILE ] 如果 FILE 存在且大小不為0則為真。
[ -t FD ] 如果文件描述符 FD 打開且指向一個終端則為真。
[ -u FILE ] 如果 FILE 存在且設置了SUID (set user ID)則為真。
[ -w FILE ] 如果 FILE 如果 FILE 存在且是可寫的則為真。
[ -x FILE ] 如果 FILE 存在且是可執(zhí)行的則為真。
[ -O FILE ] 如果 FILE 存在且屬有效用戶ID則為真。
[ -G FILE ] 如果 FILE 存在且屬有效用戶組則為真。
[ -L FILE ] 如果 FILE 存在且是一個符號連接則為真。
[ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read則為真。
[ -S FILE ] 如果 FILE 存在且是一個套接字則為真。
[ FILE1 -nt FILE2 ] 如果 FILE1 has been changed more recently than FILE2, or 如果 FILE1FILE2 does not則為真。
exists and [ FILE1 -ot FILE2 ] 如果 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在則為真。
[ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的設備和節(jié)點號則為真。
[ -o OPTIONNAME ] 如果 shell選項 “OPTIONNAME” 開啟則為真。
[ -z STRING ] “STRING” 的長度為零則為真。
[ -n STRING ] or [ STRING ] “STRING” 的長度為非零 non-zero則為真。
[ STRING1 == STRING2 ] 如果2個字符串相同。 “=” may be used instead of “==” for strict POSIX compliance則為真。
[ STRING1 != STRING2 ] 如果字符串不相等則為真。
[ STRING1 < STRING2 ] 如果 “STRING1” sorts before “STRING2” lexicographically in the current locale則為真。
[ STRING1 > STRING2 ] 如果 “STRING1” sorts after “STRING2” lexicographically in the current locale則為真。
[
ARG1 OP ARG2 ] “OP” is one of -eq, -ne, -lt, -le, -gt or -ge. These
arithmetic binary operators return true if “ARG1” is equal to, not
equal to, less than, less than or equal to, greater than, or greater
than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers.
表達式可以借以下操作符組合起來,以降序列出:listed in decreasing order of precedence: 表 7.2.
組合表達式操作 效果
[ ! EXPR ] 如果 EXPR 是false則為真。
[ ( EXPR ) ] 返回 EXPR的值。這樣可以用來忽略正常的操作符優(yōu)先級。
[ EXPR1 -a EXPR2 ] 如果 EXPR1 and EXPR2 全真則為真。
[
EXPR1 -o EXPR2 ] 如果 EXPR1 或者 EXPR2 為真則為真。 [ (或作 test)
內(nèi)建命令對條件表達式使用一系列基于參數(shù)數(shù)量的規(guī)則來求值。更多關于這個主題的信息可以在Bash文檔中查找。就像if 使用fi
來結(jié)束一樣,在條件列完之后必須用">"來結(jié)束。
7.1.1.2. 后接then語句的命令
CONSEQUENT-COMMANDS 列出了跟在 then
語句后面可以是任何有效的UNIX命令,任何可執(zhí)行的程序,任何可執(zhí)行的shell腳本或者任何shell語句,除了 fi. 。重要地記住 then
和 fi 在shell里面被認為是分開的語句。因此,在命令行上使用的時候,他們用分號隔開。
在腳本中,if語句的不同部分通常是良好分隔的。以下是一些簡單的例子:
7.1.1.3. 檢查文件
第一個例子檢查一個文件是否存在: anny ~> cat msgcheck.sh #!/bin/bash echo "This
scripts checks the existence of the messages file." echo "Checking..."
if [ -f /var/log/messages ] then echo "/var/log/messages exists." fi
echo echo "...done." anny ~> ./msgcheck.sh This scripts checks the
existence of the messages file. Checking... /var/log/messages exists.
...done.
7.1.1.4. 檢查shell選項 加入到你的Bash配置文件中去: # These lines will
print a message if the noclobber option is set: if [ -o noclobber ]
then echo "Your files are protected against accidental overwriting
using redirection." fi 環(huán)境以上的例子將在命令行輸入后開始工作: anny ~> if [ -o
noclobber ] ; then echo ; echo "your files are protected against
overwriting." ; echo ; fi your files are protected against overwriting.
anny ~>
然而,如果你使用依賴環(huán)境的測試,當你在腳本中輸入相同的命令你可能得到不用的結(jié)果,因為腳本會打開一個新的,沒有設置預期的變量和選項的shell。
7.1.2. if的簡單應用
7.1.2.1.
測試退出狀態(tài) ? 變量包含了之前執(zhí)行命令的退出狀態(tài)(最近完成的前臺進程)。 以下的例子顯示了一個簡單的測試: anny ~> if [
$? -eq 0 ] More input> then echo 'That was a good job!' More
input> fi That was a good job! anny ~> 以下的例子證明了 TEST-COMMANDS
可以是任何有返回和退出狀態(tài)的UNIX命令,之后 if 再次返回零的退出狀態(tài): anny ~> if ! grep $USER
/etc/passwd More input> then echo "your user account is not managed
locally"; fi your user account is not managed locally anny > echo $?
0 anny > 以下能得到同樣的結(jié)果: anny > grep $USER /etc/passwd anny > if [
$? -ne 0 ] ; then echo "not a local account" ; fi not a local account
anny >
7.1.2.2. 數(shù)字的比較 以下的例子是用了數(shù)值的比較: anny > num=`wc -l
work.txt` anny > echo $num 201 anny > if [ "$num" -gt "150" ]
More input> then echo ; echo "you've worked hard enough for today."
More input> echo ; fi you've worked hard enough for today. anny >
這個腳本在每個星期天由cron來執(zhí)行。如果星期的數(shù)是偶數(shù),他就提醒你把垃圾箱清理: #!/bin/bash # Calculate the
week number using the date command: WEEKOFFSET=$[ $(date +"%V") % 2 ] #
Test if we have a remainder. If not, this is an even week so send a
message. # Else, do nothing. if [ $WEEKOFFSET -eq "0" ]; then echo
"Sunday evening, put out the garbage cans." | mail -s "Garbage cans
out" your@your_domain.org
7.1.2.3. 字符串比較 一個通過比較字符串來測試用戶ID的例子:
if [ "$(whoami)" != 'root' ]; then echo "You have no permission to run $0 as non-root user." exit 1; fi 使用Bash,你可以縮短這樣的結(jié)構。
下
面是以上測試的精簡結(jié)構: [ "$(whoami)" != 'root' ] && ( echo you are using
a non-privileged account; exit 1 ) 類似于如果測試為真就執(zhí)行的 “&&” 表達式, “||”
指定了測試為假就執(zhí)行。類似于 “&&” 表達式指明了在兩個測試條件為真時所采取的動作,“||” 指明測試為假時所采取的行動。
正則表達式也可以在比較中使用: anny > gender="female" anny > if [[ "$gender" ==
f* ]] More input> then echo "Pleasure to meet you, Madame."; fi
Pleasure to meet you, Madame. anny > 真正的程序員多數(shù)程序員更喜歡使用和方括號相同作用的內(nèi)建的
test 命令,像這樣: test "$(whoami)" != 'root' && (echo you are using
a non-privileged account; exit 1) 參見信息頁面得到更多關于Bash “(( EXPRESSION ))” 和
“[[ EXPRESSION ]]” 結(jié)構的模塊匹配信息。 shell if 命令參數(shù)說明 -b 當file存在并且是塊文件時返回真 -c
當file存在并且是字符文件時返回真 -d 當pathname存在并且是一個目錄時返回真 -e 當pathname指定的文件或目錄存在時返回真
-f 當file存在并且是正規(guī)文件時返回真 -g 當由pathname指定的文件或目錄存在并且設置了SGID位時返回為真 -h
當file存在并且是符號鏈接文件時返回真,該選項在一些老系統(tǒng)上無效 -k 當由pathname指定的文件或目錄存在并且設置了“粘滯”位時返回真
-p 當file存在并且是命令管道時返回為真 -r 當由pathname指定的文件或目錄存在并且可讀時返回為真 -s
當file存在文件大小大于0時返回真 -u 當由pathname指定的文件或目錄存在并且設置了SUID位時返回真 -w
當由pathname指定的文件或目錄存在并且可執(zhí)行時返回真。一個目錄為了它的內(nèi)容被訪問必然是可執(zhí)行的。 -o
當由pathname指定的文件或目錄存在并且被子當前進程的有效用戶ID所指定的用戶擁有時返回真。
比較字符寫法:
-eq 等于
-ne 不等于
-gt 大于
-lt 小于
-le 小于等于
-ge 大于等于
-z 空串
* = 兩個字符相等
* != 兩個字符不等
* -n 非空串