Unix系列shell程式編寫:中篇
Unix系列shell程式編寫:
3>在Shell中使用資料變數
使用者可以在Shell中使用資料變數,例如ba.sh程式:
cd/usr/icewalk
ls|cpio -o > /dev/fd0
該程式中要備份的目錄為一常量,即該程式只能用來備份一個目錄。若在該程式中使用變數,則會使其更通用:
workdir=$1
cd $workdir
ls * |cpio -o > /dev/fd0
透過這一改變,使用者可以使用程式備份變數$workdir指定的目錄。例如我們要備份/home/www的內容,只要執行ba.sh
/home/www即可實現。(若不明白
$1,下面將詳細介紹shell引數的傳遞,$1代表本sh程式-ba.sh的第一個引數)
4>在Shell程式中加上註釋
為了增加程式的可讀性,我們提倡加入註釋。在Shell程式中註釋將以"#"號開始。當Shell解釋到"#"時,會認為從"#"號起一直到該行行尾為註釋。
5>對Shell變數進行算術運算
高階語言中變數是具有型別的,即變數將被限制為某一資料型別,如整數或字元型別。Shell變數通常按字元進行儲存,為了對Shell變數進行算術運算,必須使用expr命令。
expr命令將把一個算術表示式作為引數,通常形式如下:
expr [數字] [運算子] [數字]
由於Shell是按字元形式儲存變數的,所以使用者必須保證參加算術運算的運算元必須為數值。下面是有效的算術運算子:
+ 兩個整數相加
- 第一個數減去第二個數
* 兩整數相乘
/ 第一個整數除以第二個整數
% 兩整數相除,取餘數
例如:
$expr 2 + 1
結果顯示:3
$expr 5 - 3
結果顯示:2
若expr的一個引數是變數,那麼在表示式計算之前用變數值替換變數名。
$int=3
$expr $int + 4
結果顯示:7
使用者不能單純使用"*"做乘法,若輸入:
$expr 4*5
系統將會報錯,因為Shell看到"*"將會首先進行檔名替換。正確形式為:
$expr 4 * 5
結果顯示:20
多個算術表示式可以組合在一起,例如:
$expr 5 + 7 / 3
結果顯示:7
運算次序是先乘除後加減,若要改變運算次序,必須使用"`"號,如:
$int=`expr 5 + 7`
$expr $int/3
結果顯示:4
或者:
$expr `expr 5+7`/3
結果顯示:4
6>向Shell程式傳遞引數
一個程式可以使用兩種方法獲得輸入資料。一是執行時使用引數。另一種方法是互動式地獲得資料。vi編輯程式可以透過互動式的方法獲得資料,而ls和 expr則從引數中取得資料。以上兩種方法Shell程式都可以使用。在"互動式讀入資料"一節中將介紹Shell程式透過互動式的方法獲得引數。
透過命令列給Shell程式傳遞引數可以擴大程式的用途。以前面提到的ba.sh程式為例:
$cat >re.sh
cd $workdir
cpio -i < /dev/fd0
^d
程式re.sh恢復了ba.sh程式備份的所有檔案。若只從軟盤上恢復一個指定的檔案,可以用該檔名作為引數,傳遞給Shell程式re.sh:
程式改寫如下:
$cat >re2.sh
cd $workdir
cpio -i $1 < /dev/fd0
^d
使用者可以指定要恢復的檔案,例如fname
$re2.sh fname
此時檔案fname作為第一個位置引數傳遞給re2.sh,re2.sh的缺點是要恢復兩個或多個檔案要重複執行,我們可以用$*變數傳遞不確定的引數給程式:
$cat >re3.sh
cd $workdir
cpio -i $* < /dev/fd0
^d
我們就可以恢復多個檔案,例如fname1,fname2,fname3
$re3.sh fname1 fname2 fname3
(以上程式re.sh,re2.sh,re3.sh,假設使用者已經chmod了可執行權利)
因為沒有賦值的變數可以作為NULL看待,所以若是程式re3.sh在執行時候沒賦予引數,那麼一個空值將被插入到cpio命令中。該命令將恢復所有儲存的檔案。
條件判斷語句
條件判斷語句是程式設計語言中十分重要的語句,該語句的含義是當某一條件滿足時,執行指定的一組命令。
1>if - then語句
格式: if command1
then
command2
command3
fi ---(if 語句結束)
command4
每個程式或命令執行結束後都有一個返回的狀態,使用者可以用Shell變數$?獲得這一狀態。if語句檢查前面命令執行的返回狀態,若該命令成功執行,那麼在then和fi之間的命令都將被執行。在上面的命令序列中,command1和command4總要執行。若command1成功執行,command2和command3也將執行。
請看下面程式:
#unload -program to backup and remove files
cd $1
ls -a | cpio -o > /dev/mnt0
rm *
該程式在備份資料後,刪除檔案,但當cpio命令不能成功執行時,rm命令還是把資料刪除了,我們可不希望這樣,為了避免此情況,可以用if
- then語句:
#--解除安裝和判斷刪除程式
cd $1
if ls -a | cpio > /dev/mnt0
then
rm *
fi
上面程式在cpio執行成功後才刪除檔案
同時,若執行沒有成功,我們希望得到提示,sh中的echo命令可以向使用者顯示訊息,並顯示後換行,上面程式可以寫成:
#--解除安裝和判斷刪除程式
cd $1
if ls -a | cpio > /dev/mnt0
then
echo "正刪除檔案資料... ..."
rm *
fi
echo命令可以使用一些特殊的逃逸字元進行格式化輸出,下面是這些字元及其含義:
b Backspace
c 顯示後不換行
f 在終端上螢幕的開始處顯示
n 換行
r 回車
t 製表符
v 垂直製表符
反斜框
nnn 用1,2或3位8進位制整數表示一個ASCII碼字元
2>if - then - else語句
不用多說它的作用,別的高階語言中都有,格式為:
if command1
then
command2
command3
else
command4
command5
fi
在此結構中,command1中是先執行,當command1成功執行時,將執行command2和command3,否則執行command4和command5
注意看下面程式:
#備份程式
cd $1
if ls -a |cpio -o > /dev/mnt0
then
echo "刪除源資料... ..."
rm *
else
echo "磁帶備份失敗!"
fi
3>test命令進行條件測試
if語句可以透過測試命令執行的返回狀態來控制命令的執行,若要測試其他條件,在bsh中可以使用test命令。該命令檢測某一條件,當條件為真時返回0,否則返回非0值。test命令可以使Shell程式中的if語句象其他程式語言中的條件判斷語句一樣,具有很強的功能。
test命令的使用方法為:
test condition
可測試的條件分為4類:
1)測試兩個字串之間的關係。
2)測試兩個整數之間關係。
3)測試檔案是否存在或是否具有某種狀態或屬性。
4)測試多個條件的與(and)或(or)組合。
1、條件語句>>test語句
1>測試字串間的關係
bsh把所有的命令列和變數都看作字串。一些命令如expr和test可以把字元當作數字進行操作。
同樣任何數字也可以作為字串進行操作。
使用者可以比較兩個字串相等或不等,也可以測試一個串是否賦了值。有關串的運算子如下:
str1 = str2 當兩個串有相同內容、長度時為真
str1 != str2 當串str1和str2不等時為真
-n str1 當串的長度大於0時為真(串非空)
-z str1 當串的長度為0時為真(空串)
str1 當串str1為非空時為真
不但Shell程式可以使用test進行條件判斷,test命令也可以獨立執行,如:
$str1=abcd
$test $str1 = abcd
$echo $?
結果顯示:0
與上例中第一行賦值語句中的等號不同,test命令中的等號兩邊必須要有空格。本例test命令共有3個引數。注意兩個串相等必須是長度和內容都相等。
$str1="abcd "
$test "$str1" = abcd
$echo $?
結果顯示:1
上面str1包含5個字元,其中最後一個為空格符。而test命令中的另一個串只有4個字元,所以兩串不等,test返回1。
不帶任何運算子和使用-n運算子測試一個串結果是一樣的,例如:
$str1=abce
$test $str1
$echo $?
結果顯示:0
$test -n $str1
$echo $?
結果顯示:0
但是,上面兩條命令也有一點差別,反映出了使用test命令潛在的問題,請看下例:
$str1=" "
$test $str1
$echo $?
結果顯示:1
$test -n "$str1"
$echo $?
結果顯示:0
$test -n $str1
結果顯示:test:argument expected
上例中,第一次測試為假因為Shell在執行命令列之前首先要進行變數替換,即把$str1換成空格,然後shell又將命令列上的空格刪除,故 test命令測試到的為空串。而在第二次測試中,變數替換後空格位於括號內,故不會被刪除,test測試到的是一個包含空格的串,在第三次測試中,shell把空格刪除,只把-n傳個test命令,所以顯示引數錯。
2>測試兩個整數之間關係
test命令與expr命令一樣,也可以把字元轉變成整數,然後對其操作。test命令對兩個數進行比較,使用的運算子如下:
int1 -eq int2 兩數相等為真
int1 -ne int2 兩數不等為真
int1 -gt int2 int1大於int2為真
int1 -ge int2 int1大於等於int2為真
int1 -lt int2 int1小於int2為真
int1 -le int2 int1小於等於int2為真
下面的例子反映了字串比較與數字比較的不同:
$str1=1234
$str2=01234
$test $str1 = $str2
$echo $?
結果顯示:1
$test $str1 -eq $str2
$echo $?
結果顯示:0
3>有關檔案的測試
使用test進行的第三類測試是測試檔案的狀態,使用者可以測試檔案是否存在,是否可寫以及其他檔案屬性。下面是檔案測試時使用的選項。注意只有檔案存在時,才有可能為真。
-r file 使用者可讀為真
-w file 使用者可寫為真
-x file 使用者可執行為真
-f file 檔案為正規檔案為真
-d file 檔案為目錄為真
-c file 檔案為字元特殊檔案為真
-b file 檔案為塊特殊檔案為真
-s file 檔案大小非0時為真
-t file 當檔案描述符(預設為1)指定的裝置為終端時為真
4>複雜的條件測試(and 、or 、not)
-a 與
-o 或
! 非
就是組合條件了,任何高階語言中都有的(NOT 、AND 、OR),例如:
$test -r em.null -a -s em.null
$echo $?
結果顯示:1
說明了em.null並不是可讀並且非空的檔案
5>另一種執行test的方法
bsh中還有另一種執行test命令的方法,就是把測試條件放到一對[
]中,例如:
$int1=4
$[ $int1 -gt 2 ]
$echo $?
結果顯示:0
要注意在[ 的後面和 ]符號的前面要有一個空格。
下面我們用test命令寫個簡單但比較完善的程式:
#-- 備份程式
#-- 檢查引數
if [ $# -ne 1 ]
then
echo "請在程式名後面指出要備份檔案所在目錄!"
exit 1
fi
#-- 檢查目錄名是否有效
if [ ! -d "$1" ]
then
echo "$1 不是一個目錄!"
exit 2
fi
cd $1
ls -a | cpio -o >/dev/mnt0
if [ $? -eq 0 ]
then
rm *
else
echo "cpio執行不成功!備份失敗..."
exit 3
fi
6>空命令
在Bsh中用 : 代表空命令,就是充個數,什麼都不做
7>巢狀if語句和elif結構
檢查條件1
A:當條件1為真,則執行一部分操作
B:若條件1為假,檢查條件2
1)若條件2為真,執行另外一部分操作
2)若條件2為假,檢查條件3
3)若條件3為真,執行其他一部分操作
語法如下:
if command
then
command
else
if command
then
command
else
if command
then
command
fi
fi
fi
8>elif語句
巢狀if語句有時會給使用者帶來混亂,特別是什麼時候fi語句很難判斷。因此Bourne
Shell又提供了elif語句。elif是else-if的縮寫,它表示是if語句的繼續。格式為:
if command
then
command
elif command
then
command
elif command
then
command
fi
上面介紹的巢狀if語句和elif語句完成相同的功能,使用者可以根據自己的喜好選擇一種使用。
9>case語句
前面說的elif語句替代if-then-else語句,但有時在程式設計時還會遇到對同一變數進行多次的測試,該情況可以用多個elif語句實現,但還有一種更簡單的方法就是用case語句。
case語句不但取代了多個elif和then語句,還可以用變數值對多個模式進行匹配,當某個模式與變數值匹配後,其後的一系列命令將被執行,下面是case語句使用的語句。
case value in
pattem 1)
command
command;;
pattem 2)
command
command;;
....
pattem)
command;
esac
case語句只執行其中的一組命令,當變數值與多個模式相匹配時,只有第一個匹配的模式對應的命令被執行。";;"表示該模式對應的命令部分程式。
透過學習下面的read語句,我們們再舉例子說明case語句的用法。
10>read語句
Shell程式不但可以透過命令列引數得到輸入資料,還可以使用read命令提示使用者輸入資料,其語法格式為:
read var1 var2... ...varn
當Bsh遇到一個read語句時,在標準輸入檔案中讀取資料直到一個換行符。此時Shell在解釋輸入行時,不進行檔名或變數的替換,只是簡單地刪除多餘的空格。然後Shell將輸入行的第一個字的內容給變數1,第二個給變數2,直到所有變數都賦上值或是輸入行為空。若輸入行中字的個數超過變數個數,Shell將把輸入行中剩餘的所有字的內容都賦給最後一個變數。當變數個數多於輸入行字的個數時候,多於的變數將賦一個空值。輸入行的每一個字是由空格分隔的一個字母和數字組成的字串。
$read var1 var2 var3
輸入:Hello my friend
$echo $var1 $var2 $var3
結果顯示:Hello my friend
$echo $var2
結果顯示:my
下面用個read和case的例子結束本部分的學習:
#--互動式備份,恢復程式
echo "輸入要備份檔案所在目錄:c"
read WORKDIR
if [ !-d $WORKDIR ]
then
echo "Sorry,$WORKDIR is not a directory"
exit 1
fi
cd $WORKDIR
echo "輸入選擇:"
echo _
echo "1.恢復到 $WORKDIR"
echo "2.備份 $WORKDIR"
echo "0.退出"
echo
echo "c"
read CHOICE
case "$CHOICE" in
1)echo "恢復中... ..."
cpio -i < /dev/mnt0;;
2)echo "備份中... ..."
ls | cpio -o > /dev/mnt0;;
0)exit 1
*)exit 1
esac
if [ $? -ne 0 ]
then
echo "程式執行中出現錯誤!"
else
echo "操作成功!"
fi
在上面程式碼中,"*"定義了其他模式下不匹配時的預設操作。
迴圈語句
前面介紹的程式和所學的語句都是從頭到尾成一條主線下來,或是成分支結構,在日常管理UNIX的過程中,經常要重複的做一些操作,處理批次的問題,這就涉及到了迴圈結構,同高階語言相似,UNIX的Shell也提供了強大的迴圈處理語句。
Bsh語言中有三種迴圈語句-while迴圈、until迴圈、for迴圈,下面透過具體的例子分別介紹這三種結構。
While迴圈
在while迴圈語句中,當某一條件為真時,執行指定的命令。語句的結構如下:
while command
do
command
command
… …
done
示例程式碼如下:
#測試while迴圈小程式
x_t=1
while [ $x_t -lt 5 ]
do
mm=` expr $x_t * $int ` #注意""的作用
echo "$mm"
x_t=` expr $x_t + 1 ` #注意expr的用法
done
echo "THE WHILE IS END!n"
程式的執行結果如下:
1
4
9
16
THE WHILE IS END
在上述程式中,當變數x_t的值小於5的時候,執行while迴圈中的語句。在第五次迴圈時,
[ $x_t-lt5]命令返回非零值,於是程式執行done後面的程式碼。
現在利用while迴圈,可以改進我們早些時候用的備份資料的例子,當使用者指定的目錄備份完畢後,使用while迴圈使程式執行一次可以備份多個使用者指定的目錄。程式碼如下:
echo "歡迎使用備份小程式"
ANS=Y
while [ $ANS = Y -o $ANS = y ]
do
echo _
#讀目錄名
echo "輸入要備份的目錄名:c"
read DIR
if [ ! -d $DIR ]
then
echo "$DIR不是一個目錄!"
exit 1
fi
cd $DIR
echo "請選擇:"
echo _
echo "1 恢復資料到 $DIR"
echo "2 備份$DIR的資料"
echo
echo "請選擇:c"
read CHOICE
case "$CHOICE" in
1) echo "恢復中… …"
cpio -i 2) echo "備份中… …"
cpio -o >/dev/rmt0;;
*) echo "選擇無效"
esac
if [ $? -ne 0 ]
then
echo "cpio執行過程中出現問題"
exit 2
fi
echo "繼續別的目錄嗎?(Y/y)c"
read ANS
done
在程式開始,我們給變數ANS符值為Y,根據whlie的判斷條件,程式進入while迴圈,執行do-done中的語句,每次迴圈都要求使用者輸入 ANS的值用來判斷是否進行下次重複執行do-done中的語句。如果使用者輸入的條件不滿足while語句條件,迴圈結束,程式執行done後面的語句。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24790158/viewspace-1040126/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Unix系列shell程式編寫
- Unix系列shell程式編寫:下篇
- Unix系列shell程式編寫:上篇
- Shell 指令碼編寫指令碼
- 案例十:shell編寫nginx服務啟動程式Nginx
- unix下編寫socket程式的一般步驟(轉)
- shell程式設計系列程式設計
- Storm系列(三)java編寫第個storm程式ORMJava
- 走向並行系列之-使用ForkManager編寫多程式程式並行
- 編寫shell指令碼的規範指令碼
- 如何編寫高效的 Shell 指令碼指令碼
- 如何使用zx編寫shell指令碼指令碼
- JDK不同作業系統的FileSystem(unix-like)中篇JDK作業系統
- 用 C 語言寫一個簡單的 Unix Shell(1)
- 用 C 語言寫一個簡單的 Unix Shell(2)
- 在Unix下用C編寫curses程式的一些常用模組(轉)
- 技能篇:shell教程及指令碼編寫指令碼
- shell 指令碼如何編寫-致初學者指令碼
- shell編寫服務啟動指令碼指令碼
- 2、編寫/修改許可權及執行Shell程式的步驟
- Java程式編寫Java
- golang編寫程式時,shell在子目錄批量執行go mod tidyGolang
- shell程式設計學習筆記(一):編寫我的第一段程式碼程式設計筆記
- Unix Shell常用命令大全
- 編寫可靠 shell 指令碼的 8 個建議指令碼
- shell-【技術乾貨】工作中編寫shell指令碼實踐指令碼
- Sublime 編寫編譯 swift程式碼編譯Swift
- 《LINUX與UNIX SHELL程式設計指南》讀書筆記(轉)Linux程式設計筆記
- Unix下常見shell簡介(轉)
- React入門系列 – 2 編寫第一個Hello world的React程式React
- React入門系列 - 2 編寫第一個Hello world的React程式React
- 10 個實戰及面試常用 Shell 指令碼編寫面試指令碼
- Shell指令碼入門:編寫格式與執行方式指令碼
- Shell文字處理編寫單行指令的訣竅
- 前端開發常用程式碼片段(中篇)前端
- Shell入門:掌握Linux,OS X,Unix的Shell環境Linux
- shell if 寫法
- PHP 編寫守護程式PHP