- 論壇徽章:
- 0
|
Unix/Linux 平臺(tái)任務(wù)的自動(dòng)化(一)
本章要點(diǎn):
本章介紹用來(lái)替代shell腳本的工具,如TCL和perl。
本章具體包括以下內(nèi)容。
TCL/expect的使用 awk語(yǔ)言的基本知識(shí) perl語(yǔ)言的基本知識(shí)
11.1 TCL和expect
TCL是一種類似shell腳本的語(yǔ)言,你可以使用它來(lái)完成許多操作。不過(guò),我介紹它的要原因是expect是從它發(fā)展出來(lái)的。如果你想要寫一個(gè)能夠自動(dòng)處理輸入輸出的腳本(如向用戶提問(wèn)并且驗(yàn)證密碼)又不想面對(duì)C或者Perl,那么expect是你的唯一選擇。
11.1.1 TCL語(yǔ)言
要使用TCL,你必須先安裝這個(gè)程序:
% rpm -q tcl
tcl-8.0.5-30
TCL語(yǔ)言可以用交互式或者腳本的方式執(zhí)行,要使用交互式的TCL環(huán)境,只要輸入
$ tclsh
%
出現(xiàn)的"%"符號(hào)是TCL的提示符,然后就可以使用TCL命令的。
如果你要使用腳本方式的TCL,首先把你的腳本寫成一個(gè)文本文件,例如test.tcl,然后執(zhí)行
$ tclsh test.tcl
在tcl腳本中,每一行或者是一個(gè)命令行,或者是一個(gè)注釋。注釋行必須以#符號(hào)開(kāi)頭,而命令行最好以分號(hào)結(jié)束,雖然不一定要這樣做,但是這樣做可以免去不少麻煩。
變量
在tcl中,有兩種基本類型的變量,即標(biāo)量和數(shù)組。標(biāo)量就是一般的數(shù)字或者字符串變量,可以用set語(yǔ)句定義同時(shí)賦值:
% set i 1
1
字符串應(yīng)該用引號(hào)括起來(lái):
% set str "test"
'test'
要輸出一個(gè)標(biāo)量的內(nèi)容,使用put語(yǔ)句:
% puts $str
test
$用來(lái)說(shuō)明str是一個(gè)變量。puts函數(shù)在標(biāo)準(zhǔn)輸出顯示變量的內(nèi)容。
數(shù)組也可以用set語(yǔ)句定義,實(shí)際上,tcl中建立數(shù)組只是單個(gè)建立數(shù)組的元素。例如 ,
% set arr(1) 0
0
% set arr(2) 1
1
這樣就建立了一個(gè)兩個(gè)元素的數(shù)組arr。在TCL中,不存在相當(dāng)于數(shù)組邊界這樣的東西,例如
% set arr(100) to
to
這時(shí)數(shù)組中實(shí)際只存在arr(1),arr(2)和arr(100),這是和C語(yǔ)言不同的地方。用array size命令可以返回?cái)?shù)組的大。
% array size arr
3
訪問(wèn)數(shù)組的方法和訪問(wèn)標(biāo)兩實(shí)際是一樣的,例如:
% puts $arr(100)
to
可以用同樣的方法創(chuàng)建多維數(shù)組。
要使用數(shù)組中的所有元素,需要使用一種特殊的便利方式。首先要啟動(dòng)startsearsh:
% array startsearch arr
s-1-arr
這里返回了一個(gè)搜索id,你可以把它傳遞給某個(gè)變量,因?yàn)橐院筮要使用它進(jìn)行進(jìn)一步的搜索:
% set my_id [array startsearch arr]
s-1-arr
現(xiàn)在my_id的內(nèi)容是s-1-arr,然后,就可以搜索arr的內(nèi)容了:
% array nextelement arr $my_id
whi
這里的array nextelement返回的是什么?可能有點(diǎn)出乎你的意料,是arr數(shù)組的下標(biāo),再執(zhí)行一次array nextelement命令又會(huì)找出另外一個(gè)下標(biāo):
% array nextelement arr $my_id
4
這樣遍歷下去,可以找出arr數(shù)組的所有下標(biāo),而知道下標(biāo)之后,就可以用$arr(4)之類的方式訪問(wèn)arr的內(nèi)容了。當(dāng)遍歷完成之后,array nextelement命令將簡(jiǎn)單地返回:
% array nextelement arr $my_id
%
這時(shí)就可以停止遍歷過(guò)程了,如果你想確認(rèn)遍歷是否完成,可以使用array anymore命令:
% array anymore arr $my_id
0
返回0說(shuō)明遍歷已經(jīng)完成。
串處理
TCL中可以進(jìn)行一般的串處理過(guò)程,這可以使用string命令和append命令,append命令將某個(gè)字符串加到另外一個(gè)字符串的后面:
% set str1 "test "
test
% set str2 "cook it"
cook it
% append str1 $str2 " and other"
test cook it and other
string命令可以執(zhí)行字符串的比較,刪除和查詢,其格式是 string [參數(shù)] string1 [string2]
參數(shù)可以是下面的命令之一:
compare 按照字典順序?qū)ψ址M(jìn)行比較,根據(jù)相對(duì)關(guān)系返回-1,0或者+1。
first 返回string2中第一次出現(xiàn)string1的位置,如果失敗,返回-1。
last 返回string2中最后一次出現(xiàn)string1的位置,如果失敗,返回-1
trim 從string1中刪除開(kāi)頭和結(jié)尾的出現(xiàn)在string2中的字符
trimleft 從string1中刪除開(kāi)頭的出現(xiàn)在string2中的字符。
trimright 從string1中刪除結(jié)尾的出現(xiàn)在string2中的字符
下面幾個(gè)用在string中的參數(shù)不需要string2變量:
length 返回tring1的長(zhǎng)度
tolower 返回將string1全部小寫化的串
toupper 返回將string1全部大寫化的串
運(yùn)算
TCL的運(yùn)算方式比較別扭,它使用expr命令作為計(jì)算符號(hào),其用法類似C語(yǔ)言的+=和/= ,例如,
% set j [expr $i/5]
1
注意TCL會(huì)自動(dòng)選擇整數(shù)或者浮點(diǎn)計(jì)算:
% set l [ expr $i /4.0]
1.25
% set l [ expr $i /4]
1
在TCL里面可以使用+ - * /和%作為基本運(yùn)算符,另外通常還包括一些數(shù)學(xué)函數(shù),如abs,sin,cos,exp和power(乘方)等等。
另外,還有一個(gè)起運(yùn)算符作用的命令incr,它用來(lái)對(duì)變量加一:
% set i 1
1
% incr i
2
流程控制
tcl支持分支和循環(huán)。分支語(yǔ)句可以使用if和switch實(shí)現(xiàn)。if語(yǔ)句的和C語(yǔ)言類似,如
if { $ x "
send "o 202.199.248.11\r"
expect {
"Connected" break
"refused" { sleep 10} ;
}
}
這
里使用了我們?cè)趖cl語(yǔ)言中講到的while和break命令,熟悉C的讀者應(yīng)該很容易看出它的行為:不斷地等待ftp>提示符,在提示符下面發(fā)送
連接遠(yuǎn)端服務(wù)器的命令,如果服務(wù)器回應(yīng)是refused(連接失。,就等待10秒鐘,然后開(kāi)始下一次循環(huán);如果是Connected,那么就跳出循環(huán)執(zhí)
行下面的命令。sleep是expect的一個(gè)標(biāo)準(zhǔn)命令,表示暫停若干秒鐘。
expect還支持許多更復(fù)雜的進(jìn)程控制方式,如fork,disconnect等等,你可以從手冊(cè)頁(yè)面中得到詳細(xì)的信息。另外,各種tcl運(yùn)算符和流程控制命令,包括tcl函數(shù)也可以使用。
有
些讀者可能會(huì)問(wèn),如果expect執(zhí)行的話是否控制臺(tái)輸入不能使用了,答案是否定的。expect命令運(yùn)行時(shí),如果某個(gè)等待的信息沒(méi)有得到,那么程序會(huì)阻
塞在相應(yīng)的expect語(yǔ)句處,這時(shí),你在鍵盤上輸入的東西仍然可以正常地傳遞到程序中去,其實(shí)對(duì)于那些expect處理的信息,原則上你輸入的內(nèi)容仍然
有效,只是expect的反映太快,總是搶在你的前面“輸入”就是了。知道了這一點(diǎn)之后,你就可能寫一個(gè)expect腳本,讓expect自動(dòng)處理來(lái)自
fscki的那些惡心的yes/no選項(xiàng)(我們介紹過(guò),這些yes/no其實(shí)完全是多余的,正常情況下你除了選擇yes之外什么也干不了)。
缺省下,expect在標(biāo)準(zhǔn)輸出(你的終端上)輸出所有來(lái)自應(yīng)用程序的回應(yīng)信息,你可以用下面的兩個(gè)命令重定向這些信息:
log_file [文件名]
這個(gè)命令讓expect在你設(shè)置的文件中記錄輸出信息。必須注意,這個(gè)選項(xiàng)并不影響控制臺(tái)輸出信息,不過(guò)如果你通過(guò)crond設(shè)置expect腳本在半夜運(yùn)行的話,你就確實(shí)可能需要這個(gè)命令來(lái)記錄各種信息了。例如:
log_file expect.log
log_user 0/1
這個(gè)選項(xiàng)設(shè)置是否顯示輸出信息,設(shè)置為1時(shí)是缺省值,為0 的話,expect將不產(chǎn)生任何輸出信息,或者說(shuō)簡(jiǎn)單地過(guò)濾掉控制臺(tái)輸出。必須記住,如果你用log_user 0關(guān)閉了控制臺(tái)輸出,那么你同時(shí)也就關(guān)閉了對(duì)記錄文件的輸出。
這一點(diǎn)很讓人困擾,如果你確實(shí)想要記錄expect的輸出卻不想讓它在控制臺(tái)上制造垃圾的話,你可以簡(jiǎn)單地把expect的輸出重定向到/dev/null:
./test.exp > /dev/null
你可以象下面這樣使用一對(duì)fork和disconnect命令。expect的disconnect命令將使得相應(yīng)的進(jìn)程到后臺(tái)執(zhí)行,輸入和輸出被重定向到/dev/null:
if [fork]!=0 exit
disconnect
fork命令會(huì)產(chǎn)生出一個(gè)子進(jìn)程,而且它產(chǎn)生返回值,如果返回的是0,說(shuō)明這是一個(gè)子進(jìn)程,如果不為0,那么是父進(jìn)程。因此,執(zhí)行了fork命令之后,父進(jìn)程死亡而子進(jìn)程被disconnect命令放到后臺(tái)執(zhí)行。注意disconnect命令只能對(duì)子進(jìn)程使用。
11.2 awk和文件的處理
UNIX里面充斥著各種記錄文件和類似的東西。對(duì)文本文件的處理是系統(tǒng)管理員每天重要的工作,例如從系統(tǒng)記錄中查找重要的內(nèi)容,或者對(duì)某種程序的輸出進(jìn)行統(tǒng)計(jì)等等。我們將介紹常用的一個(gè)處理程序,即gawk。
11.2.1 grep和正則表達(dá)式
讓我們首先從grep命令開(kāi)始。這個(gè)命令大家應(yīng)該很熟悉了,它用來(lái)在文件中查找一個(gè)字符串。不過(guò),實(shí)際上,grep的處理功能要強(qiáng)大和復(fù)雜的多。
grep 命令的語(yǔ)法是
grep [模式] [文件名]
如果沒(méi)有給出文件名,就缺省使用標(biāo)準(zhǔn)輸入。grep每次讀取一行,并且和給出的模式進(jìn)行匹配,如果成功就把這一行會(huì)顯,例如:(粗體的是我們輸入的內(nèi)容)
$ grep test
close
test my hand
test my hand
grep的“模式”也稱為正則表達(dá)式,可以由各種基本的正則表達(dá)式元素構(gòu)成。正則表達(dá)式元素主要包括下面幾種:
字符串 匹配任何字符串,例如grep test表示在標(biāo)準(zhǔn)輸入中1
[...] 封閉集中匹配一個(gè)字符,如:[abcde]可以匹配a,b,c,d,e
[^...] 求補(bǔ)集中匹配一個(gè)字符,例如[^ABC]匹配
. 匹配任意字符
\s 空白符
\S 非空白符
\d 數(shù)字
\D 非數(shù)字
\w 字母或數(shù)字
\W 非字母和數(shù)字
* 匹配任何字符
上面的形式是grep中使用的基本正則表達(dá)式,另外,還可以使用egrep,egrep是grep的一個(gè)擴(kuò)展版本,支持下面這些擴(kuò)展的正則字符串:
^ 匹配一行的開(kāi)始
$ 匹配一行的結(jié)尾
( ) 確定正則表達(dá)式求值順序,和正常演算中的括號(hào)意思差不多。
(...|...|...) 或,可選項(xiàng)之一進(jìn)行匹配,例如:(abc|dev|ghi)可以匹配abc,dev,ghi,而(ww|gg)do可以匹配wwdo或者ggdo。
+ 一次或多次模式
如:aba+匹配aba,abaa...不匹配ab
通常,我們有兩種方法使用grep和egrep,一種是使用管道,例如我們應(yīng)該熟悉的ps ax |grep sendmail,另一種是直接在文件中搜索對(duì)應(yīng)的字符串。
grep/egrep還可以在命令行使用開(kāi)關(guān),常用的開(kāi)關(guān)包括:
-b 在行前加上塊號(hào)
-c 統(tǒng)計(jì)匹配行的個(gè)數(shù)
-n 在行前加上行號(hào)
-w 將模式解釋為字符串,所有正則表達(dá)式的控制命令失效
-x 精確匹配
-r 查詢文件時(shí)包含子目錄
舉個(gè)例子來(lái)說(shuō),我們想在/var/log/httpd/access_log中查詢所有不是來(lái)自本地(192.168.0.1)的請(qǐng)求記錄,可以執(zhí)行:
grep –v "^192.168.0.1" /var/log/httpd/access_log
^用來(lái)讓grep 只在行首匹配。
在grep查詢的時(shí)候可以使用通配符代表多個(gè)文件,例如,grep start * -r將在當(dāng)前目錄以及所有子目錄的所有文件中查詢start字符串。
11.2.2 gawk的使用方法
gawk是awk的一個(gè)實(shí)現(xiàn),awk是一種用來(lái)處理報(bào)告等文本文件的腳本語(yǔ)言。不過(guò),我們介紹這個(gè)產(chǎn)品的主要目標(biāo)是用它來(lái)處理各種程序的記賬文件。對(duì)于復(fù)雜的腳本,還是用Perl比較合適。
gawk 的
主要功能是針對(duì)檔案的每一行搜尋指定的 模式。,每當(dāng)找到一個(gè)匹配的模式,gawk就會(huì)去執(zhí)行你設(shè)定的動(dòng)作。按照這個(gè)方式, gawk 依此方式處理輸入
檔案的每一行直到輸入檔案結(jié)束。如果對(duì)于某個(gè)模式?jīng)]有設(shè)置對(duì)應(yīng)的動(dòng)作,gawk將直接將這個(gè)行顯示出來(lái)。
為了使用gawk,你通常必須先寫一個(gè)awk腳本,除非模式/動(dòng)作非常簡(jiǎn)單,可以在一行上完成。我們用一個(gè)例子來(lái)解釋gawk的基本用法,首先產(chǎn)生一個(gè)目錄列表文件:
ls –l /etc > list
現(xiàn)在list的內(nèi)容有點(diǎn)像這樣:
total 2164
drwxr-xr-x 3 root root 4096 Feb 15 22:55 CORBA
-rw-r--r-- 1 root root 2045 Sep 24 1999 DIR_COLORS
-rw-r--r-- 1 root root 17 Mar 25 19:59 HOSTNAME
…………
現(xiàn)在我們選擇一個(gè)最簡(jiǎn)單的例子,簡(jiǎn)單地查找所有屬性是drwxr-xr-x的目錄文件:
gawk '/drwxr-xr-x/ {print $0}' list
將輸出所有這樣的目錄。
這個(gè)例子看上去沒(méi)有什么實(shí)際用處,因?yàn)橛胓rep也可以做同樣的動(dòng)作,那么我們可以看一看下面這個(gè)功能:
$ gawk '$1=="-rwxr-xr-x" {sum=sum+$5} END {print sum}' list
15041
這個(gè)是什么意思?對(duì)于所有屬性是755的文件,讓gawk對(duì)第五欄的數(shù)字求和。第五欄我們可以看到就是文件的長(zhǎng)度,因此這個(gè)命令將顯示所有屬性為755的文件的總共的長(zhǎng)度。
$n是gawk中非常重要的概念,它用來(lái)表示文本串的分欄。缺省的情況下,gawk將輸入字符串(從文件中讀入的每一行)按照分割的空格分成若干個(gè)字段,每個(gè)字段作為一個(gè)變量,例如有一行
my name is 3th test
那
么,在awk讀入這一行之后,就產(chǎn)生了$1到$5變量,其中$1="my",$2="is",……… ,最后$5="test"。另外還有一個(gè)特殊的變
量$0,它表示整個(gè)輸入行,也就是這個(gè)字符串"my name is test"。另外還有一個(gè)特殊的變量NF,它表示當(dāng)前行的字段的個(gè)數(shù),在現(xiàn)在的情況
下,NF應(yīng)該等于5。
在某些特殊的情況下,你可能需要改變分割符的定義,這可以通過(guò)對(duì)FS賦值來(lái)完成,例如FS=","將分割符定義為都號(hào)而不是缺省的空格。
在
一般情況下,gawk可以從命令文件中獲得模式/動(dòng)作,命令文件的格式很簡(jiǎn)單,就是直接將應(yīng)該寫在命令行上的模式/動(dòng)作對(duì)寫在文件里面,每個(gè)對(duì)構(gòu)成一行,
模式可以有兩種,一種是模式匹配,也就是我們?cè)谇懊娼忉尩恼齽t表達(dá)式,如果使用正則表達(dá)式,那么需要用兩個(gè)/把它們夾在一起,例如/[A-Z]/表示正則
表達(dá)式[A-Z]。
另一種模式是比較指令,比較指令可以用比較操作符和邏輯運(yùn)算符來(lái)構(gòu)成,常用的比較操作符有:
== 等于 = 不小于 !~ 按照正則表達(dá)式不匹配
> 大于 != 不等于
邏輯運(yùn)算符有
&& 和 || 或 ! 非 ()括號(hào)
設(shè)定了模式后,就可以設(shè)置對(duì)應(yīng)的動(dòng)作了,在gawk中,動(dòng)作必須用花括號(hào)括起來(lái)。ga
wk能完成的動(dòng)作并不多,畢竟它是一種報(bào)告分析語(yǔ)言。一般情況下,只要熟悉print和p
rintf命令就足夠了,print命令的格式非常簡(jiǎn)單:
print item1,item2,…………
輸出時(shí),每個(gè)項(xiàng)目輸出一欄,中間用空格分開(kāi)。一個(gè)print后面不跟著任何變量會(huì)導(dǎo)致gawk顯示當(dāng)前的輸入行($0)。如果要輸出一個(gè)字符串,使用引號(hào)把它括起來(lái),特別是如果要輸出一個(gè)空行,使用print ""。這里是一個(gè)例子,它將list文件的頭兩欄輸出:
gawk '{print $1,$2}' list
由于輸入的文本文件內(nèi)容有多行,你在命令欄中設(shè)計(jì)的模式/動(dòng)作會(huì)對(duì)每一行執(zhí)行一次。就是:
total 2164
drwxr-xr-x 3
-rw-r--r-- 1
-rw-r--r-- 1
-rw-r--r-1
…………………
如果你要精確地控制輸出,也可以使用printf命令,這個(gè)命令的格式是:
printf format, item1, item2, ...
format參數(shù)就是C語(yǔ)言里面的格式控制符,例如%c,%d,%f等等。在 % 與格式控制字母之間可加入 modifier,modifier 是用來(lái)進(jìn)一步控制輸出的格式。可能的 modifier 如下所示:
'-' 使用在 width 之前,指明是向左靠齊。如果'-'沒(méi)有出現(xiàn),則會(huì)在被指定的寬度向右靠齊。例如:
printf "%-4S", "foo"會(huì)印出'foo '。
'width' 這一個(gè)數(shù)字指示相對(duì)應(yīng)的欄位印出時(shí)的寬度。例如:
printf "%4s","foo" 會(huì)印出' foo'。
width 的值是一個(gè)最小寬度而非最大寬度。如果一個(gè) item 的值需要的寬度比 width 大,則不受 width 的影響。例如printf "%4s","foobar"將印出'foobar'。
'.prec' 此數(shù)字指定印出時(shí)的精確度。它指定小數(shù)點(diǎn)右邊的位數(shù)。如果是要印出一個(gè)字串,它指定此字串最多會(huì)被印出多少個(gè)字符。
作為一種腳本語(yǔ)言,gawk允許使用變量,定義變量非常簡(jiǎn)單,就是直接用等號(hào)對(duì)它賦值。為了在gawk程序的開(kāi)始處對(duì)變量賦值,gawk專門提供了BEGIN語(yǔ)句,這個(gè)語(yǔ)句將在所有行被讀入之前執(zhí)行,而且只執(zhí)行一次,通常用它來(lái)執(zhí)行初始化命令,例如
BEGIN { sum=0;count=0;average=0.0;}
對(duì)于變量可以使用數(shù)學(xué)表達(dá)式進(jìn)行運(yùn)算,運(yùn)算符包括常見(jiàn)的加減乘除算符,以及^(乘方),%(取余)和著名的++,--。不過(guò)注意gawk在做除法的時(shí)候總是使用浮點(diǎn)除法,除了取余算符%。
函數(shù)
另外,gawk包含下列函數(shù):
數(shù)學(xué)函數(shù)
atan2(x,y) y/x的正切
cos(x) 余弦函數(shù)
sin(x) 正弦函數(shù)
int(x) 取整
log(x) 取自然對(duì)數(shù)
exp(x) 指數(shù)函數(shù)
rand(x) 生成一個(gè)0到1之間的隨機(jī)數(shù)
srand() 初始化隨機(jī)數(shù)發(fā)生器
systime() 返回從1970年1月1日0:00到當(dāng)前時(shí)間的秒數(shù)
sqrt(x) 取x的平方根
字符串函數(shù)
index(string1,string2 )
它會(huì)在string1 里面,尋找string2 第一次出現(xiàn)的地方,返回值是字串string2出現(xiàn)在字串string1 里面的位置。如果找不到,返回值為 0。
例如:
print index("peanut","an")
會(huì)印出 3。
length(string)
string字符串的長(zhǎng)度
例如:
length("abcde")
是 5。
match(string,regexp)
match 函
數(shù)會(huì)在字串 string 里面,尋找符合 regexp 的最長(zhǎng)、最靠左邊的子字串。返回值是 regexp 在 string 的開(kāi)始位置,
即 index值。這個(gè)函數(shù)會(huì)設(shè)定內(nèi)部變量 RSTART 等於 index,內(nèi)部變量RLENGTH 等於符合的子串個(gè)數(shù)。如果不符合,則會(huì)設(shè)
定 RSTART 為0、RLENGTH 為 -1。
sprintf(format,expression1,...)
跟C語(yǔ)言的sprintf差不多。
例如:
sprintf("pi = %.2f (approx.)',22/7)
傳回的字串為"pi = 3.14 (approx.)"
sub(regexp, replacement,target)
在字串 target 里面,尋找符合 regexp 的最長(zhǎng)、最靠左邊的地方,并且以字串 replacement 代替最左邊的 regexp。
例如:
str = "water, water, everywhere"
sub(/at/, "ith",str)
結(jié)果字串str會(huì)變成
"wither, water, everywhere"
gsub(regexp, replacement, target)
gsub 與前面的 sub 類似。在字串 target 里面,尋找符合 regexp 的所有地方,以字串 replacement 代替所有的 regexp。
例如:
str="water, water, everywhere"
gsub(/at/, "ith",str)
結(jié)果字串str會(huì)變成
'wither, wither, everywhere"
substr(string, start, length)
傳回字串 string 的子字串,這個(gè)子字串的長(zhǎng)度為 length 個(gè)字符,從第 start 個(gè)位置開(kāi)始。
例如:
substr("washington",5,3)
傳回值為"ing"
如果 length 沒(méi)有出現(xiàn),則傳回的子字串是從第 start 個(gè)位置開(kāi)始至結(jié)束。
例如:
substr("washington",5)
傳回值為"ington"
tolower(string)
將字串string的大寫字母改為小寫字母。
例如:
tolower("MiXeD cAsE 123")
傳回值為"mixed case 123"
toupper(string)
將字串string的小寫字母改為大寫字母。
例如:
toupper("MiXeD cAsE 123")
傳回值為"MIXED CASE 123"
其他函數(shù)
system(command)
此函式允許使用者執(zhí)行作業(yè)系統(tǒng)的指令,執(zhí)行完畢後將回到 gawk 程式。
例如:
BEGIN {system("ls")}
控制流
在gawk命令腳本中可以使用控制流,主要是if,for,while等語(yǔ)句,用法和C語(yǔ)言相當(dāng)類似:
if (condition) then-body [else else-body]
如果 condition 為真(true),則執(zhí)行 then-body,否則執(zhí)行 else-body。
舉一個(gè)例子如下:
if (x % 2 == 0)
print "x is even"
else
print "x is odd"
while (condition)
body
while 語(yǔ)
句測(cè)試 condition表達(dá)式。假如 condition 為真則執(zhí)行 body 的語(yǔ)句。一次執(zhí)行完後,會(huì)再測(cè)試 condition,假如
condition 為真,則 body 會(huì)再度被執(zhí)行。這個(gè)過(guò)程會(huì)一直被重復(fù)直到condition 不再是真。如果 condition 第一次測(cè)試
就是偽(false),則body 從沒(méi)有被執(zhí)行。
下面的例子會(huì)印出每個(gè)輸入行的前三個(gè)欄位。
gawk '{ i=1
while (i <= 3) {
print $i
i++
}
}'
do
body
while (condition)
這個(gè) do loop 執(zhí)行 body 一次,然後只要 condition 是真則會(huì)重復(fù)執(zhí)行 body。即使開(kāi)始時(shí) condition 是偽,body 也會(huì)被執(zhí)行一次。
下面的例子會(huì)印出每個(gè)輸入記錄十次。
gawk '{ i= 1
do {
print $0
i++
} while (i <= 10)
}'
for (initialization; condition; increment)
body
此敘述開(kāi)始時(shí)會(huì)執(zhí)行initialization,然後只要 condition是真,它會(huì)重復(fù)執(zhí)行body與做increment 。
下面的例子會(huì)印出每個(gè)輸入記錄的前三個(gè)欄位。
gawk '{ for (i=1; i<=3; i++)
print $i
}'
break 會(huì)跳出包含它的 for、while、do-while 循環(huán)的最內(nèi)層。
下面的例子會(huì)找出任何整數(shù)的最小除數(shù),它也會(huì)判斷是否為質(zhì)數(shù)。
gawk '# find smallest divisor of num
{ num=$1
for (div=2; div*div <=num; div++)
if (num % div == 0)
break
if (num % div == 0)
printf "Smallest divisor of %d is %d\n", num, div
else
printf "%d is prime\n", num }'
continue 使用于 for、while、do-while 循環(huán)內(nèi)部,它會(huì)跳過(guò)循環(huán)體的剩余部分,立刻進(jìn)行下一次循環(huán)的執(zhí)行。
下面的例子會(huì)印出 0 至 20 的全部數(shù)字,但是 5 并不會(huì)被印出。
gawk 'BEGIN {
for (x=0; x<=20; x++) {
if (x==5)
continue
printf ("%d",x)
}
print ""
}'
next 語(yǔ)句強(qiáng)迫 gawk 立刻停止處理目前的行而繼續(xù)下一個(gè)輸入行。
exit 語(yǔ)句會(huì)使得 gawk 程式停止執(zhí)行而跳出。然而,如果 END 出現(xiàn),它會(huì)去執(zhí)行 END 的 actions。
自定義函數(shù)
你可以定義自己的函數(shù),其格式是
function name (parameter-list) {
body-of-function
}
name 是所定義的函數(shù)名字。 parameter-list 是函數(shù)的變量列表。變量間使用逗號(hào)分開(kāi)。
函數(shù)可以在程序的任何地方定義,不過(guò)習(xí)慣上總是定義在程序的開(kāi)頭部分。
下面這個(gè)例子,會(huì)將每個(gè)記錄的第一個(gè)欄位之值的平方與第二個(gè)欄位之值的平方加起來(lái)。
{print "sum =",SquareSum($1,$2)}
function SquareSum(x,y) {
sum=x*x+y*y
return sum
}
如果你熟悉任何編程語(yǔ)言,那么掌握awk都是很輕松的事情,如果你不喜歡它,那么你可以參考我們下面介紹的perl。
本文來(lái)自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u2/70515/showart_1161114.html |
|