Linux中的腳本編程2010-04-09 10:54
linux腳本(shell)編程
linux 下最重要的腳本語言算是 bash 了,我也就寫點這個吧(我也只會這個:))。跟其他開發(fā)語言(如C)比,bash是比較簡單的一種語言,主要用于寫一些腳本代碼,一些批處理或安裝程序。你可以看看在/etc/init.d/目錄下,那里就有很多用來控制各個服務(wù)的腳本文件。
先看一個“hello world!”的例子:
在某個目錄下新建一個文件,叫hello.sh,敲入以下代碼:
#!/bin/sh
echo "hello world!"
好,就這些。保存,在命令提示符下進(jìn)入保存“hello.sh”的目錄,這樣執(zhí)行:
#sh hello.sh(回車)
看到了吧?哈哈,不過你高興的不要太早了,只并不能說明什么,就象你在其他編程環(huán)境中做的“hello world.”一樣,離高手的距離還遠(yuǎn)著呢。
我們先看看bash腳本中變量的使用。
修改上面的“hello world!”的例子,改成下面的樣子:
#!/bin/bash
# This is a very simple example
str="hello world!"
echo $ str
保存后按照上面的方法執(zhí)行該腳本,你將看到和以前一樣的效果。我們看看每一句的意義:
第一行,#! 是說明 hello.sh 這個文件的類型的,有點類似 Windows 系統(tǒng)下用文件后綴來表示不同文件類型的意思。Linux系統(tǒng)根據(jù) "#!" 及該字串后面的信息確定該文件的類型。在 BASH 中第一行的 "#!" 及后面的 "/bin/bash" 就表明該文件是一個BASH 程序,需要由 /bin 目錄下的 bash 程序來解釋執(zhí)行。BASH 這個程序一般是存放在 /bin 目錄下。這一行的寫法是固定的。
第二行的 "# This is a ..." 就是 BASH 程序的注釋,在 BASH 程序中從“#”號(沒有“!”號)開始到行尾的部分均被看作是程序的注釋,相當(dāng)于C/C++語言中的“//”。
第三行是為一個名稱為 str 的變量賦值。
第四行的 echo 語句的功能是把 echo 后面的字符串或變量的內(nèi)容輸出到標(biāo)準(zhǔn)輸出中去。需要注意的是 BASH 中的絕大多數(shù)語句結(jié)尾處都沒有分號。
對于第三行,可能有人會問:在C/C++中,變量都屬于某個類型,在這變量 str 的類型是什么呢?在 BASH 中變量定義是不需要的,沒有"int i"這樣的定義過程。如果想用一個變量,只要他沒有在前面被定義過,就直接可以用,當(dāng)然你使用該變量的第一條語句應(yīng)該是對他賦初值了,如果你不賦初值也沒關(guān)系,只不過該變量是空(注意:是 NULL,不是 0 )。
關(guān)于變量的使用,要注意以下幾點:
一,變量賦值時,“=”左右兩邊都不能有空格;
二,BASH 中的語句結(jié)尾不需要分號(";");
三,除了在變量賦值和在FOR循環(huán)語句頭中,BASH 中的變量使用必須在變量前加"$ "符號。
在比較詳細(xì)的 bash 文檔中,會規(guī)定使用變量要采用這樣的形式:$ {STR},如果你的腳本出了莫名其妙的錯誤,不妨看看是不是這個問題造成的。
BASH 中的變量既然不需要定義,也就沒有類型一說,那是不是一個變量既可以存放整數(shù),也可以存放字符串呢?對!
一個變量即可以被定義為一個字符串,也可以被再定義為整數(shù)。如果對該變量進(jìn)行整數(shù)運(yùn)算,他就被解釋為整數(shù);如果對他進(jìn)行字符串操作,他就被看作為一個字符串。請看下面的例子:
#!/bin/bash
x=2006
let "x = $ x + 1"
echo $ x
x="a string."
echo $ x
執(zhí)行一下看看?
又出現(xiàn)了新的關(guān)鍵字:let。關(guān)于整數(shù)變量計算,有如下幾種:" + - * / %",他們的意思和字面意思相同,在*和/之前必須冠以反斜線,已防被SHELL先行解釋。整數(shù)運(yùn)算一般通過 let 和 expr這兩個指令來實現(xiàn),如對變量 x 加 1 可以寫作:let "x = $ x + 1" 或者 x=`expr $ x + 1`
關(guān)于運(yùn)行時參數(shù),我們在執(zhí)行腳本時有時很想傳個參數(shù)進(jìn)去,如:#sh mysh.sh hdz(回車)好,很簡單,在 bash 中,使用這樣傳進(jìn)來的變量時也要在前面加“$ ”符號。
$ # 傳入腳本的命令行參數(shù)個數(shù);
$ * 所有命令行參數(shù)值,在各個參數(shù)值之間留有空格;
位置變元
$ 0 命令本身(shell文件名)
$ 1 第一個命令行參數(shù);
$ 2 第二個命令行參數(shù);
...
好,編輯以下腳本:
#!/bin/sh
echo "number of vars:"$ #
echo "values of vars:"$ *
echo "value of var1:"$ 1
echo "value of var2:"$ 2
echo "value of var3:"$ 3
echo "value of var4:"$ 4
保存文件名為 my.sh,執(zhí)行時傳入?yún)?shù):#sh my.sh a b c d e(回車),看到結(jié)果你就會更清楚各個變量的意思。如果訪問的參數(shù)在執(zhí)行時沒有傳入,如有一條這樣的代碼:
echo "value of var4:"$ 100
而在執(zhí)行時并沒有輸入100個參數(shù),那取得的值為 NULL。
在 BASH 程序中如果一個變量被使用了,那么直到該程序的結(jié)尾,該變量都一直有效。為了使得某個變量存在于一個局部程序塊中,就引入了局部變量的概念。BASH 中,在變量首次被賦初值時加上 local 關(guān)鍵字就可以聲明一個局部變量,如下面這個例子:
#!/bin/bash
HELLO="var1"
echo $ HELLO
function hello {
local HELLO="var2"
echo $ HELLO
}
echo $ HELLO
該程序的執(zhí)行結(jié)果是:
var1
var2
var1
這個執(zhí)行結(jié)果表明全局變量 $ HELLO 的值在執(zhí)行函數(shù) hello 時并沒有被改變。也就是說局部變量 $ HELLO 的影響只存在于函數(shù)那個程序塊中。
BASH 中的變量與 C 語言中變量的區(qū)別
這里我們?yōu)樵瓉聿皇煜?BASH 編程,但是非常熟悉 C 語言的程序員總結(jié)一下在 BASH 環(huán)境中使用變量需要注意的問題。
1,BASH 中的變量在引用時都需要在變量前加上 "$ " 符號( 第一次賦值及在For循環(huán)的頭部不用加 "$ "符號 );
2,BASH 中沒有浮點運(yùn)算,因此也就沒有浮點類型的變量可用;
3,BASH 中的整形變量的比較符號與 C 語言中完全不同,而且整形變量的算術(shù)運(yùn)算也需要經(jīng)過 let 或 expr 語句來處理;
下面我們來看看變量之間的比較操作:
在比較操作上,整數(shù)變量和字符串變量各不相同,詳見下表:
對應(yīng)的操作 整數(shù)操作 字符串操作
相同 -eq =
不同 -ne !=
大于 -gt >
小于 -lt <
大于或等于 -ge
小于或等于 -le
為空 -z
不為空 -n
比如:
比較整數(shù) a 和 b 是否相等就寫做 if [ $ a = $ b ]
判斷整數(shù) a 是否大于整數(shù) b 就寫做 if [ $ a -gt $ b ]
比較字符串 a 和 b 是否相等就寫作:if [ $ a = $ b ]
判斷字符串 a 是否為空就寫作: if [ -z $ a ]
判斷整數(shù)變量 a 是否大于 b 就寫作:if [ $ a -gt $ b ]
注意:在“[”和“]”符號的左右都留有空格。
BASH 是 Linux 操作系統(tǒng)的 Shell,因此系統(tǒng)的文件必然是 BASH 需要操作的重要對象
運(yùn)算符,下面說說對文件的操作:
含義( 滿足下面要求時返回 TRUE )
-e 文件已經(jīng)存在
-f 文件是普通文件
-s 文件大小不為零
-d 文件是一個目錄
-r 文件對當(dāng)前用戶可以讀取
-w 文件對當(dāng)前用戶可以寫入
-x 文件對當(dāng)前用戶可以執(zhí)行
-g 文件的 GID 標(biāo)志被設(shè)置
-u 文件的 UID 標(biāo)志被設(shè)置
-O 文件是屬于當(dāng)前用戶的
-G 文件的組 ID 和當(dāng)前用戶相同
file1 -nt file2 文件 file1 比 file2 更新
file1 -ot file2 文件 file1 比 file2 更老
如 if [ -x /root ] 可以用于判斷 /root 目錄是否可以被當(dāng)前用戶進(jìn)入。
上面有進(jìn)行比較的 if 關(guān)鍵字,是的,bash 中有和 C 語言相似的流程控制語句,主要有:if、for、while、until、case 等語句。下面較詳細(xì)的介紹一下。
if 語句用于判斷和分支,其語法規(guī)則和 C 語言的 if 非常相似。其幾種基本結(jié)構(gòu)為:
if [ expression_r ]
then
#code block
fi
或者
if [ expression_r ]
then
#code block
else
#code block
fi
或者
if [ expression_r ]
then
#code block
else if [ expression_r ]
then
#code block
else
#code block
fi
或者
if [ expression_r ]
then
#code block
elif [ expression_r ]
then
#code block
else
#code block
fi
如果您為了簡潔,想把 then 和 if 放在一行,那就要這樣寫了:if [ expression_r ]; then。即在 then前加一個“;”號(bash 里面每行的結(jié)束處沒有分號,那要把兩行的內(nèi)容寫到一行,是不是要用“;”號隔開?。抗?,對!這樣說來,“if [expression_r ]; then”只是把兩行內(nèi)容寫到了一行,沒有什么新的東西。)。
for 循環(huán)結(jié)構(gòu)與 C 語言中有所不同,在 BASH 中 for 循環(huán)的基本結(jié)構(gòu)是:
for $ var in
do
#code block
done
其中 $ var 是循環(huán)控制變量, 是 var 需要遍歷的一個集合,do/done 對包含了循環(huán)體,相當(dāng)于 C語言中的一對大括號。另外如果do 和 for 被寫在同一行,必須在 do 前面加上 ";"。如: for $ var in ; do。下面是一個運(yùn)用 for 進(jìn)行循環(huán)的例子:
#!/bin/bash
for day in Sun Mon Tue Wed Thu Fri Sat
do
echo $ day
done
# 如果列表被包含在一對雙引號中,則被認(rèn)為是一個元素
for day in "Sun Mon Tue Wed Thu Fri Sat"
do
echo $ day
done
exit 0
注意上面的例子中,在 for 所在那行的變量 day 是沒有加 "$ " 符號的,而在循環(huán)體內(nèi),echo 所在行變量 $day 是必須加上 "$ " 符號的。另外如果寫成 for day 而沒有后面的 in 部分,則 day將取遍命令行的所有參數(shù)。如這個程序:
#!/bin/bash
for param
do
echo $ param
done
exit 0
上面這個程序?qū)⒘谐鏊忻钚袇?shù)。for 循環(huán)結(jié)構(gòu)的循環(huán)體被包含在 do/done 對中,這也是后面的 while、until 循環(huán)所具有的特點。
while 循環(huán)的基本結(jié)構(gòu)是:
while [ condition ]
do
#code block
done
這個結(jié)構(gòu)請大家自己編寫一個例子來驗證。
until 循環(huán)的基本結(jié)構(gòu)是:
until [ condition is TRUE ]
do
#code block
done
這個結(jié)構(gòu)也請大家自己編寫一個例子來驗證。
case
BASH 中的 case 結(jié)構(gòu)與 C 語言中的 switch 語句的功能比較類似,可以用于進(jìn)行多項分支控制。其基本結(jié)構(gòu)是:
case "$ var" in
condition1 )
;;
condition2 )
;;
* )
default statments;;
esac
下面這個程序是運(yùn)用 case 結(jié)構(gòu)進(jìn)行分支執(zhí)行的例子:
#!/bin/bash
echo "Hit a key, then hit return."
read Keypress
case "$ Keypress" in
[a-z] ) echo "Lowercase letter";;
[A-Z] ) echo "Uppercase letter";;
[0-9] ) echo "Digit";;
* ) echo "Punctuation, whitespace, or other";;
esac
exit 0
上面例子中的第四行 "read Keypress" 一句中的 read 語句表示從鍵盤上讀取輸入。這個命令將在本講義的 BASH 的其他高級問題中講解。
break/continue
熟悉 C 語言編程的都很熟悉 break 語句和 continue 語句。BASH 中同樣有這兩條語句,而且作用和用法也和 C語言中相同,break 語句可以讓程序流程從當(dāng)前循環(huán)體中完全跳出,而 continue 語句可以跳過當(dāng)次循環(huán)的剩余部分并直接進(jìn)入下一次循環(huán)。
關(guān)于bash在控制臺下的快捷鍵
ctrl+u 刪除光標(biāo)以前的所有字符
ctrl+d 刪除光標(biāo)以前的一個字符
ctrl+k 刪除光標(biāo)以后的所有字符
ctrl+h 刪除光標(biāo)以后的一個字符
ctrl+t 調(diào)換光標(biāo)前兩個字符的次序
ctrl+a 移動光標(biāo)到最前面
ctrl+e 移動光標(biāo)到最后面
ctrl+p 上一個命令
ctrl+n 下一個命令
ctrl+s 鎖定輸入
ctrl+q 解除鎖定
ctrl+f 移動光標(biāo)到后一個字符
ctrl+b 移動光標(biāo)到前一個字符
ctrl+x 標(biāo)記一個位置
ctrl+c 清除當(dāng)前的輸入