本篇內(nèi)容均摘自《Linux命令行與shell腳本編程大全》尼酿,個(gè)人認(rèn)為需要重點(diǎn)學(xué)習(xí)的章節(jié)。【免費(fèi)】Linux命令行與Shell腳本編程大全 第3版 PDF全本 21MB 百度網(wǎng)盤下載 - 今夕是何夕 - 博客園
許多程序要求對(duì)shell腳本中的命令施加一些邏輯流程控制涎永。有一類命令會(huì)根據(jù)條件使腳本跳過某些命令鹿响。這樣的命令通常稱為結(jié)構(gòu)化命令( structured command)。結(jié)構(gòu)化命令允許你改變程序執(zhí)行的順序妈倔。
使用 if-then 語句
最基本的結(jié)構(gòu)化命令就是if-then語句绸贡。 if-then語句有如下格式:
if command
then
commands
fi
如果該命令的退出狀態(tài)碼(參見第11章)是0(該命令成功運(yùn)行)听怕,位于then部分的命令就會(huì)被執(zhí)行。如果該命令的退出狀態(tài)碼是其他值闽烙, then部分的命令就不會(huì)被執(zhí)行声搁, bash shell會(huì)繼續(xù)執(zhí)行腳本中的下一個(gè)命令疏旨。 fi語句用來表示if-then語句到此結(jié)束。這里有個(gè)簡單的例子可解釋這個(gè)概念莫换。
$ cat test1.sh
#!/bin/bash
# testing the if statement
if pwd
then
echo "It worked"
fi
這個(gè)腳本在if行采用了pwd命令骤铃。如果命令成功結(jié)束惰爬, echo語句就會(huì)顯示該文本字符串。在命令行運(yùn)行該腳本時(shí)陵叽,會(huì)得到如下結(jié)果:
$ ./test1.sh
/home/Christine
It worked
shell執(zhí)行了if行中的pwd命令丛版。由于退出狀態(tài)碼是0,它就又執(zhí)行了then部分的echo語句胖替。下面是另外一個(gè)例子独令。
$ cat test2.sh
#!/bin/bash
# testing a bad command
if IamNotaCommand
then
echo "It worked"
fi
echo "We are outside the if statement"
$ ./test2.sh
./test2.sh: line 3: IamNotaCommand: command not found
We are outside the if statement
在這個(gè)例子中好芭,我們在if語句行故意放了一個(gè)不能工作的命令舍败。由于這是個(gè)錯(cuò)誤的命令,所以它會(huì)產(chǎn)生一個(gè)非零的退出狀態(tài)碼裙戏,且bash shell會(huì)跳過then部分的echo語句弛说。還要注意,運(yùn)行if語句中的那個(gè)錯(cuò)誤命令所生成的錯(cuò)誤消息依然會(huì)顯示在腳本的輸出中信柿。
[說明] 你可能在有些腳本中看到過if-then語句的另一種形式:
if command; then
commands
fi
通過把分號(hào)放在待求值的命令尾部渔嚷,就可以將then語句放在同一行上了稠曼,這樣看起來更像其他編程語言中的if-then語句。在then部分漠吻,你可以使用不止一條命令途乃。可以像在腳本中的其他地方一樣在這里列出多條命令烫饼。 bash shell會(huì)將這些命令當(dāng)成一個(gè)塊试读,如果if語句行的命令的退出狀態(tài)值為0钩骇,所有的命令都會(huì)被執(zhí)行;如果if語句行的命令的退出狀態(tài)不為0韩容,所有的命令都會(huì)被跳過唐瀑。
$ cat test3.sh
#!/bin/bash
# testing multiple commands in the then section
#
testuser=Christine
#
if grep $testuser /etc/passwd
then
echo "This is my first command"
echo "This is my second command"
echo "I can even put in other commands besides echo:"
ls -a /home/$testuser/.b*
fi
if語句行使用grep命令在/etc/passwd文件中查找某個(gè)用戶名當(dāng)前是否在系統(tǒng)上使用哄辣。如果有用戶使用了那個(gè)登錄名,腳本會(huì)顯示一些文本信息并列出該用戶HOME目錄的bash文件毅弧。
$ ./test3.sh
Christine:x:501:501:Christine B:/home/Christine:/bin/bash
This is my first command
This is my second command
I can even put in other commands besides echo:
/home/Christine/.bash_history /home/Christine/.bash_profile
/home/Christine/.bash_logout /home/Christine/.bashrc
但是当窗,如果將testuser變量設(shè)置成一個(gè)系統(tǒng)上不存在的用戶崖面,則什么都不會(huì)顯示。
$ cat test3.sh
#!/bin/bash
# testing multiple commands in the then section
#
testuser=NoSuchUser
#
if grep $testuser /etc/passwd
then
echo "This is my first command"
echo "This is my second command"
echo "I can even put in other commands besides echo:"
ls -a /home/$testuser/.b*
fi
$ ./test3.sh
$
如果在這里顯示的一些消息可說明這個(gè)用戶名在系統(tǒng)中未找到庶香,這樣可能就會(huì)顯得更友好赶掖。是的,可以用if-then語句的另外一個(gè)特性來做到這一點(diǎn)陪白。
If-then-else語句
在if-then語句中呈驶,不管命令是否成功執(zhí)行袖瞻,你都只有一種選擇拆吆。如果命令返回一個(gè)非零退出狀態(tài)碼, bash shell會(huì)繼續(xù)執(zhí)行腳本中的下一條命令枣耀。在這種情況下霉晕,如果能夠執(zhí)行另一組命令就好了。這正是if-then-else語句的作用捞奕。
if-then-else語句在語句中提供了另外一組命令牺堰。
if command
then
commands
else
commands
fi
當(dāng)if語句中的命令返回退出狀態(tài)碼0時(shí), then部分中的命令會(huì)被執(zhí)行颅围,這跟普通的if-then語句一樣伟葫。當(dāng)if語句中的命令返回非零退出狀態(tài)碼時(shí), bash shell會(huì)執(zhí)行else部分中的命令≡捍伲現(xiàn)在可以復(fù)制并修改測試腳本來加入else部分筏养。
$ cp test3.sh test4.sh
$
$ nano test4.sh
$
$ cat test4.sh
#!/bin/bash
# testing the else section
#
testuser=NoSuchUser
#
if grep $testuser /etc/passwd
then
echo "The bash files for user $testuser are:"
ls -a /home/$testuser/.b*
echo
else
echo "The user $testuser does not exist on this system."
echo
fi
$ ./test4.sh
The user NoSuchUser does not exist on this system.
$
這樣就更友好了常拓。跟then部分一樣渐溶, else部分可以包含多條命令。 fi語句說明else部分結(jié)束了弄抬。
嵌套if
要檢查/etc/passwd文件中是否存在某個(gè)用戶名以及該用戶的目錄是否尚在茎辐,可以使用嵌套的if-then語句。嵌套的if-then語句位于主if-then-else語句的else代碼塊中掂恕。
$ ls -d /home/NoSuchUser/
/home/NoSuchUser/
$
$ cat test5.sh
#!/bin/bash
# Testing nested ifs
#
testuser=NoSuchUser
#
if grep $testuser /etc/passwd
then
echo "The user $testuser exists on this system."
else
echo "The user $testuser does not exist on this system."
if ls -d /home/$testuser/
then
echo "However, $testuser has a directory."
fi
fi
$ ./test5.sh
The user NoSuchUser does not exist on this system.
/home/NoSuchUser/
However, NoSuchUser has a directory.
這個(gè)腳本準(zhǔn)確無誤地發(fā)現(xiàn)拖陆,盡管登錄名已經(jīng)從/etc/passwd中刪除了,但是該用戶的目錄仍然存在竹海。在腳本中使用這種嵌套if-then語句的問題在于代碼不易閱讀慕蔚,很難理清邏輯流程≌洌可以使用else部分的另一種形式: elif孔飒。這樣就不用再書寫多個(gè)if-then語句了灌闺。 elif使用另一個(gè)if-then語句延續(xù)else部分。
if command1
then
commands
elif command2
then
more commands
fi
elif語句行提供了另一個(gè)要測試的命令坏瞄,這類似于原始的if語句行桂对。如果elif后命令的退出狀態(tài)碼是0,則bash會(huì)執(zhí)行第二個(gè)then語句部分的命令鸠匀。使用這種嵌套方法蕉斜,代碼更清晰,邏輯更易懂缀棍。
$ cat test5.sh
#!/bin/bash
# Testing nested ifs - use elif
testuser=NoSuchUser
if grep $testuser /etc/passwd
then
echo "The user $testuser exists on this system."
#
elif ls -d /home/$testuser
then
echo "The user $testuser does not exist on this system."
echo "However, $testuser has a directory."
#
fi
$ ./test5.sh
/home/NoSuchUser
The user NoSuchUser does not exist on this system.
However, NoSuchUser has a directory.
甚至可以更進(jìn)一步宅此,讓腳本檢查擁有目錄的不存在用戶以及沒有擁有目錄的不存在用戶。這可以通過在嵌套elif中加入一個(gè)else語句來實(shí)現(xiàn)爬范。
$ cat test5.sh
#!/bin/bash
# Testing nested ifs - use elif & else
testuser=NoSuchUser
if grep $testuser /etc/passwd
then
echo "The user $testuser exists on this system."
elif ls -d /home/$testuser
then
echo "The user $testuser does not exist on this system."
echo "However, $testuser has a directory."
else
echo "The user $testuser does not exist on this system."
echo "And, $testuser does not have a directory."
fi
$ ./test5.sh
/home/NoSuchUser
The user NoSuchUser does not exist on this system.
However, NoSuchUser has a directory.
$ sudo rmdir /home/NoSuchUser
[sudo] password for Christine:
$
$ ./test5.sh
ls: cannot access /home/NoSuchUser: No such file or directory
The user NoSuchUser does not exist on this system.
And, NoSuchUser does not have a directory.
在/home/NoSuchUser目錄被刪除之前父腕,這個(gè)測試腳本執(zhí)行的是elif語句,返回零值的退出狀態(tài)青瀑。因此elif的then代碼塊中的語句得以執(zhí)行璧亮。刪除了/home/NoSuchUser目錄之后, elif語句返回的是非零值的退出狀態(tài)斥难。這使得elif塊中的else代碼塊得以執(zhí)行枝嘶。記住,在elif語句中哑诊,緊跟其后的else語句屬于elif代碼塊群扶。它們并不屬于之前的if-then代碼塊。
可以繼續(xù)將多個(gè)elif語句串起來搭儒,形成一個(gè)大的if-then-elif嵌套組合穷当。
if command1
then
command set 1
elif command2
then
command set 2
elif command3
then
command set 3
elif command4
then
command set 4
fi
每塊命令都會(huì)根據(jù)命令是否會(huì)返回退出狀態(tài)碼0來執(zhí)行。記住淹禾, bash shell會(huì)依次執(zhí)行if語句馁菜,只有第一個(gè)返回退出狀態(tài)碼0的語句中的then部分會(huì)被執(zhí)行。