網(wǎng)站實(shí)例營銷策劃咨詢機(jī)構(gòu)
一、變量
gawk編程語言支持兩種變量:內(nèi)建變量和自定義變量。
1、內(nèi)建變量
gawk使用內(nèi)建變量來引用一些特殊的功能。
字段和記錄分隔符變量
數(shù)據(jù)字段變量
此變量允許使用美元符號(hào)($)和字段在記錄中的位置值來引用對(duì)應(yīng)的字段。要引用記錄中的第一個(gè)數(shù)據(jù)字段,就用變量 $1,要引用第二個(gè)數(shù)據(jù)字段,就用變量 $2,以此類推。
數(shù)據(jù)字段由字段分隔符劃定。默認(rèn)情況下,字段分隔符是一個(gè)空白字符:空格或制表符??梢酝ㄟ^使用命令行選項(xiàng) -F ,或者使用特殊的內(nèi)建變量 FS 修改字段分隔符。
FIELDWIDTHS | 由空格分隔的一列數(shù)字,定義了每個(gè)數(shù)據(jù)字段的確切寬度 |
FS | 輸入字段分隔符 |
RS | 輸入記錄分隔符 |
OFS | 輸出字段分隔符 |
ORS | 輸出記錄分隔符 |
?默認(rèn)情況下,gawk會(huì)將OFS變量的值設(shè)置為一個(gè)空格。print命令會(huì)自動(dòng)將OFS變量的值置于輸出的每個(gè)字段之間。
gawk 'BEGIN{FS=","} {print $1,$2,$3}' test2.txt
可以通過設(shè)置0FS變量,可以在輸出中用任意字符串來分隔字段。
gawk 'BEGIN{FS=","; OFS="*"} {print $1,$2,$3}' test2.txt
?FIELDWIDTHS變量可以不通過字段分隔符讀取記錄。一旦設(shè)置了此變量,gawk就會(huì)忽略FS變量,并根據(jù)提供的字段寬度計(jì)算字段。
gawk 'BEGIN{FIELDWIDTHS="2 4 5 3"} {print $1,$2,$3,$4}' test3.txt
變量RS和ORS定義了gawk對(duì)數(shù)據(jù)流中記錄的處理方式。默認(rèn)情況下,gawk會(huì)將RS和ORS設(shè)置為換行符。
默認(rèn)的RS值表明,輸入數(shù)據(jù)流中的每行文本就是一條記錄。
?包含地址和電話號(hào)碼的數(shù)據(jù)中,占據(jù)了多行
可以把FS變量設(shè)置成換行符,這樣就表明數(shù)據(jù)流中的每一行都是一個(gè)單獨(dú)的字段,行內(nèi)的所有數(shù)據(jù)都屬于同一個(gè)數(shù)據(jù)字段。同時(shí)把RS變量設(shè)置成空字符串,然后在數(shù)據(jù)記錄之間留一個(gè)空行。gawk就會(huì)把每一個(gè)空行視為記錄分隔符。
gawk 'BEGIN{FS="\n"; RS=""} {print $1,$3}' test3.txt
gawk將文件中的每一行都視為一個(gè)字段,同時(shí)將空行作為記錄分隔符。?
?數(shù)據(jù)變量
ENVIRON變量使用關(guān)聯(lián)數(shù)組來提取shell環(huán)境變量,其中關(guān)聯(lián)數(shù)組用文本而非數(shù)值作為數(shù)組索引。
如下所示,可以用這種方法從shell中提取任何環(huán)境變量的值,以供gawk腳本使用。
gawk '
BEGIN{
print ENVIRON["HOME"]
print ENVIRON["PATH"]
}'
?變量FNR、NF和NR用于在gawk腳本中跟蹤數(shù)據(jù)字段和記錄。
變量NF可以讓用戶在不知道具體位置的情況下引用記錄中的最后一個(gè)數(shù)據(jù)字段。NF變量含有數(shù)據(jù)文件中的最后一個(gè)字段的編號(hào),在其前面加上美元符號(hào),就把它用作字段變量。
gawk 'BEGIN{FS=":" ; OFS=":"} {print $1,$NF}' /etc/passwdgawk 'BEGIN{FS=":" ; OFS=":"} {$NF}' /etc/passwd
注意看執(zhí)行兩條命令后打印出來的區(qū)別之處。?
?FNR變量包含當(dāng)前數(shù)據(jù)文件中已處理過的記錄數(shù),NR變量包含已處理過的記錄總數(shù)。
gawk 'BEGIN{FS=","}{print $1, "FNR="FNR}' test2.txt test2.txt
上述gawk腳本在命令行中指定了兩個(gè)輸入文件(都是test2.txt),此腳本會(huì)打印第一個(gè)字段和FNR變量的當(dāng)前值。?
gawk 'BEGIN{FS=","}{print $1, "FNR="FNR, "NR="NR}
END{print "這兒總共有",NR,"條記錄被處理了"}'' test2.txt test2.txt
?在gawk處理第二個(gè)數(shù)據(jù)文件時(shí),FNR變量的值被重置了,而NR變量則繼續(xù)計(jì)數(shù)。
?因此,如果只使用一個(gè)數(shù)據(jù)文件作為輸入,那么FNR和NR的值是相同的;如果使用多個(gè)數(shù)據(jù)文件作為輸入,那么FNR的值會(huì)在處理每個(gè)數(shù)據(jù)文件時(shí)被重置,NR的值則會(huì)繼續(xù)計(jì)數(shù)直到處理完所有的數(shù)據(jù)文件。
?2、自定義變量
gawk自定義變量的名稱由任意數(shù)量的字母、數(shù)字和下劃線組成,但不能以數(shù)字開頭。而且,其變量名區(qū)分大小寫。
在腳本中給變量賦值
在gawk腳本中給變量賦值與給shell腳本中的變量賦值一樣,都使用賦值語句。
gawk '
BEGIN{
test1="測(cè)試……"
print test1
}'
?也可以保存數(shù)值或文本值:
gawk '
BEGIN{
test1="測(cè)試……"
print test1
test1=89
print test1
}'
還可以處理數(shù)學(xué)算式:
gawk 'BEGIN{x=7; x=x *9 + 10; print x}'
?在命令行中給變量賦值
可以在不修改腳本代碼的情況下改變腳本的行為。
BEGIN{FS=","}
{print $n}
gawk -f test.sh n=3 test2.txt
?通過上述命令,可以顯示文件中的第3個(gè)字段(n=3)。
使用命令行參數(shù)來定義變量值會(huì)產(chǎn)生一個(gè)問題:在設(shè)置過變量之后,這個(gè)值在腳本的BEGIN部分不可用。
BEGIN{print "開始值是",n; FS=","}
{print $n}
gawk -f test.sh n=3 test2.txt
使用 -v 選項(xiàng)解決該問題,它允許在BEGIN部分之前設(shè)定變量。它必須放在腳本代碼之前。
gawk -v n=3 -f test.sh test2.txt
?二、數(shù)組
gawk使用關(guān)聯(lián)數(shù)組來提供數(shù)組的功能。與數(shù)字型數(shù)組不同,關(guān)聯(lián)數(shù)組的索引可以是任意文本字符串,它用各種字符串來引用數(shù)組元素,每個(gè)索引字符串都必須能夠唯一地標(biāo)識(shí)出分配給它的數(shù)組元素。就跟其它語言中的哈希表、字典類似。
1、定義數(shù)組變量
使用標(biāo)準(zhǔn)賦值語句定義數(shù)組變量。
格式:var[index] = element
var:變量名;index:關(guān)聯(lián)數(shù)組的索引值;element:數(shù)組元素值
gawk 'BEGIN{
capital["中國"] = "北京"
print capital["中國"]
}'
?2、遍歷數(shù)組變量
在gawk腳本中遍歷關(guān)聯(lián)數(shù)組,使用for語句的一種特殊形式。
for {var in array}
{
?statements
}
此for語句會(huì)在每次循環(huán)時(shí)將關(guān)聯(lián)數(shù)組array的下一個(gè)索引值賦給變量var,然后執(zhí)行一遍statements。變量var中存儲(chǔ)的是索引而不是數(shù)組元素值。
gawk 'BEGIN{
var["a"] = 10
var["h"] = 190
var["k"] = 78
var["t"] = "hello"
for (test in var)
{print "索引:",test," - 值:", var[test]
}
}'
如下所示,索引值沒有固定的返回順序。?
3、刪除數(shù)組變量
?從關(guān)聯(lián)數(shù)組中刪除數(shù)組元素要使用一個(gè)特殊的命令:
delete array[index]
delete命令會(huì)從關(guān)聯(lián)數(shù)組中刪除索引值及其相關(guān)的數(shù)組元素值。
gawk 'BEGIN{
var["a"] = 10
var["h"] = 190
var["k"] = 78
var["t"] = "hello"
for (test in var)
{print "索引:",test," - 值:", var[test]
}delete var["k"]
print "*****"
for (test in var)
{ print "索引:",test," - 值:", var[test]
}
}'
三、使用模式
?gawk支持幾種類型的匹配模式來過濾數(shù)據(jù)記錄。比如,關(guān)鍵字BEGIN和END可以在讀取數(shù)據(jù)流之前或之后執(zhí)行命令的特殊模式。
1、正則表達(dá)式
可以使用基礎(chǔ)正則表達(dá)式(BRE)或擴(kuò)展正則表達(dá)式(ERE)來篩選數(shù)據(jù)。
在使用正則表達(dá)式時(shí),它必須出現(xiàn)在與其對(duì)應(yīng)腳本的左花括號(hào)前。
# 匹配含有字符串“11”的數(shù)據(jù)
gawk 'BEGIN{FS=","} /11/{print $1}' test2.txt
#匹配用作字段分隔符的逗號(hào)
gawk 'BEGIN{FS=","} /,d/ {print $1}' test2.txt
2、匹配操作符
?匹配操作符(~)是一個(gè)很強(qiáng)大的工具,可以將正則表達(dá)式限制在記錄的特定數(shù)據(jù)字段??梢灾付ㄆヅ洳僮鞣?、數(shù)據(jù)字段變量以及要匹配的正則表達(dá)式。
$1 ~ /^data/:此表達(dá)式會(huì)過濾出第一個(gè)數(shù)據(jù)字段以data開頭的所有記錄。
gawk 'BEGIN{FS=","} $2 ~ /^data3/{print $0}' test2.txt
匹配第2個(gè)數(shù)據(jù)字段要以“data3”開頭的數(shù)據(jù)。?
可以用它在文件中搜索特定的數(shù)據(jù)元素。
gawk -F: '$1 ~ /csb/{print $1, $NF}' /etc/passwd
上面的腳本命令會(huì)在第一個(gè)數(shù)據(jù)字段中查找文本“csb”,如果匹配成功,則打印出第一個(gè)數(shù)據(jù)字段和最后一個(gè)數(shù)據(jù)字段。?
?也可以使用 ! 符號(hào)來排除正則表達(dá)式的匹配:
$1 !~ /expression/
gawk -F: '$1 !~ /^csb/{print $1,$NF}' /etc/passwd
匹配第一個(gè)數(shù)據(jù)字段不是以“csb”開頭的數(shù)據(jù),?如果匹配成功,則打印出第一個(gè)數(shù)據(jù)字段和最后一個(gè)數(shù)據(jù)字段。
3、數(shù)學(xué)表達(dá)式
顯示出所有屬于root用戶組(組ID為0)的用戶。
下面的gawk腳本會(huì)檢查記錄中值為0的第四個(gè)字段。?
gawk -F: '$4 == 0{print $1}' /etc/passwd
?也可以對(duì)文本數(shù)據(jù)使用表達(dá)式,但跟正則表達(dá)式不同,表達(dá)式必須完全匹配。
gawk -F, '$1 == "data"{print $1}' test2.txtgawk -F, '$1 == "data21"{print $1}' test2.txt
四、結(jié)構(gòu)化命令
?1、if 語句
gawk編程語言支持標(biāo)準(zhǔn)格式的 if-then-else 語句。
gawk '{
if ($1 > 30)
{x = $1 * 2print x
}
}' test3.txt
gawk '{
if ($1 < 30)
{x = $1 * 2print x
} else
{x = $1 / 2print x
}}' test3.txt
?
?也可以在單行中使用else語句。
gawk '{if ($1 < 30) print $1 * 2; else print $1 / 2}' test3.txt
2、while語句
gawk '{
total = 0
i = 1
while (i <=3)
{total += $ii++
}
avg = total / 3
print "平均值是:", avg
}' test1.txt
還可以使用break語句和continue語句
gawk '{
total = 0
i = 1
while (i <= 3)
{total += $iif (i == 2)breaki++
}
avg = total / 2
print "前兩個(gè)數(shù)據(jù)的平均值是:", avg
}' test1.txt
?
3、do-while語句
do-while語句與while語句類似,但會(huì)在檢查條件語句之前先執(zhí)行命令。
gawk '{
total = 0
i = 1
do
{total += $ii++
} while (total < 200)
print total
}' test1.txt
4、for語句
gawk '{
total = 0
for (i = 1; i <=3; i++)
{total += $i
}
avg = total /3
print "平均值是:",avg
}' test1.txt
五、格式化打印
和C語言編程一樣,gawk中的格式化打印命令 printf 可以控制如何顯示數(shù)據(jù)
格式:printf "format string, var1, var2
format string是格式化輸出的關(guān)鍵,它會(huì)用文本元素和格式說明符來具體指定如何呈現(xiàn)格式化輸出。格式說明符是一種特殊的代碼,可以指明顯示什么類型的變量以及如何顯示。
1、控制字母
gawk腳本會(huì)將每個(gè)格式說明符作為占位符,供命令中的每個(gè)變量使用。第一個(gè)格式說明符對(duì)應(yīng)列出第一個(gè)變量,第二個(gè)對(duì)應(yīng)第二個(gè)變量,以此類推。
c | 將數(shù)字作為ASCII字符顯示 |
d | 顯示整數(shù)值 |
i | 顯示整數(shù)值 |
e | 用科學(xué)計(jì)數(shù)法顯示數(shù)字 |
f | 顯示浮點(diǎn)值 |
g | 用科學(xué)計(jì)數(shù)法或浮點(diǎn)數(shù)顯示(較短的格式優(yōu)先) |
o | 顯示八進(jìn)制值 |
s | 顯示字符串 |
x | 顯示十六進(jìn)制值 |
X | 用大寫字母顯示十六進(jìn)制值 |
gawk 'BEGIN{
x = 10 * 10000
printf "結(jié)果是:%e\n", x
}'
?2、修飾符
除了控制字母,還有3種修飾符可以進(jìn)一步控制輸出。
width
指定輸出字段的最小寬度。如果輸出短于這個(gè)值,則printf會(huì)將文本右對(duì)齊,并用空格進(jìn)行填充。如果輸出比指定的寬度長,則按實(shí)際長度輸出。
prec
指定浮點(diǎn)數(shù)中小數(shù)點(diǎn)右側(cè)的位數(shù)或者字符串中顯示的最大字符數(shù)。
減號(hào) -?
指明格式化空間中的數(shù)據(jù)采用左對(duì)齊而非右對(duì)齊
在同一行中打印多個(gè)輸出。
gawk 'BEGIN{FS=","} {printf "%s ", $1} END{printf "\n"}' test2.txt
?使用修飾符格式化第一個(gè)字符串的值
gawk 'BEGIN{FS="\n"; RS=""} {printf "%10s %s\n", $1, $2}' test1.txt
使用printf處理浮點(diǎn)值?
gawk '{
total = 0
for (i = 1; i <=3; i++)
{total += $i
}
avg = total / 3
printf "平均值是:%8.1f\n",avg
}' test3.txt
%8.1f強(qiáng)制printf命令將浮點(diǎn)值近似到小數(shù)點(diǎn)后一位。?
六、內(nèi)置函數(shù)?
gawk編程語言提供了一些內(nèi)置函數(shù)用于執(zhí)行一些常見的數(shù)學(xué)、字符串以及時(shí)間運(yùn)算。
1、數(shù)學(xué)函數(shù)
atan(x,y) | x/y的反正切,x和y以弧度為單位 |
cos(x) | x的余弦,x以弧度為單位 |
exp(x) | x的指數(shù) |
int(x) | x的整數(shù)部分,取靠近0一側(cè)的值 |
log(x) | x的自然對(duì)數(shù) |
rand() | 比0大且比1小的隨機(jī)浮點(diǎn)數(shù) |
sin(x) | x的正弦,x以弧度為單位 |
sqrt(x) | x的平方根 |
srand(x) | 為計(jì)算隨機(jī)數(shù)指定一個(gè)種子值 |
and(v1,v2) | 對(duì)v1和v2執(zhí)行按位AND運(yùn)算 |
comp1(v1) | 對(duì)v1執(zhí)行補(bǔ)運(yùn)算 |
lshift(val,count) | 將val左移count位 |
or(v1,v2) | 對(duì)v1和v2執(zhí)行按位OR運(yùn)算 |
rshift(val,count) | 將val右移count位 |
xor(v1,v2) | 對(duì)v1和v2執(zhí)行按位XOR運(yùn)算 |
?產(chǎn)生較大隨機(jī)整數(shù)的常見方法是綜合運(yùn)用rand()函數(shù)和int()函數(shù):
x = int(10 * rand())
上述命令會(huì)返回一個(gè)0~9(包括0和9)的隨機(jī)整數(shù)值。
2、字符串函數(shù)
index(s,t) | 返回字符串t在字符串s中的索引位置;如果沒找到,則返回0 |
length([s]) | 返回字符串s的長度;如果沒有指定,則返回$0的長度 |
match(s,r [,a]) | 返回正則表達(dá)式r在字符串s中匹配位置的索引。如果指定了數(shù)組a,則將s的匹配部分保存在該數(shù)組中 |
split(s,a [,r]) | 將s以FS(字段分隔符)或正則表達(dá)式r(如果有指定的話)分割并放入數(shù)組a中。返回分割后的字段總數(shù) |
sub(r,s [,t]) | 在變量$0或目標(biāo)字符串t中查找匹配正則表達(dá)式r的部分。如果找到了,就用字符串s替換第一處匹配 |
substr(s,i [,n]) | 返回s中從索引 i 開始、長度為n的子串。如果未提供n,則返回s中剩下的部分 |
tolower(s) | 將s中的所有字符都轉(zhuǎn)換成小寫 |
toupper(s) | 將s中的所有字符都轉(zhuǎn)換成大寫 |
gawk 'BEGIN{x = "ning"; print toupper(x); print length(x)}'
3、時(shí)間函數(shù)
時(shí)間函數(shù)多用于處理日志文件。日志文件中一般含有需要進(jìn)行比較的日期。通過將日期的文本表示形式轉(zhuǎn)換成紀(jì)元時(shí)(自1970-01-01 00:00:00 UTC到現(xiàn)在的秒數(shù)),可以做到很容易就比較日期。
mktime(dataspec) | 將一個(gè)按YYYY MM DD HH MM SS [DST]格式指定的日期轉(zhuǎn)換成時(shí)間戳 |
strftime(format [, timestamp]) | 將當(dāng)前時(shí)間的時(shí)間戳或timestamp(如果提供了的話)轉(zhuǎn)化成格式化日期(采用shell命令date的格式) |
systime() | 返回當(dāng)前時(shí)間的時(shí)間戳 |
gawk 'BEGIN{
date = systime()
day = strftime("%A, %B %d, %Y", date)
print day
}'
?
七、自定義函數(shù)
?可以在gawk腳本中自己創(chuàng)建函數(shù)。
1、定義函數(shù)
定義自己的函數(shù),必須使用function關(guān)鍵字。
function name([variables])
{??
? statements
}
function myrand(limit)
{ return int(limit * rand())
}
2、使用自定義函數(shù)
定義函數(shù)時(shí),它必須出現(xiàn)在所有代碼塊之前(包括BEGIN代碼塊)。
gawk '
function myrand(limit)
{ return int(limit * rand())
}
BEGIN{x = myrand(8)print x
}'
3、創(chuàng)建函數(shù)庫
gawk提供了一種方法可以將多個(gè)函數(shù)放入單個(gè)庫文件中。
首先,創(chuàng)建一個(gè)包含所有g(shù)awk函數(shù)的文件
# 函數(shù)庫名:functionlib
function myrand(limit)
{ return int(limit * rand())
}function myprint()
{printf "%-16s - %s\n", $1, $4
}function printthird()
{print $3
}
接著,使用函數(shù)庫時(shí),只要?jiǎng)?chuàng)建好gawk腳本文件,然后在命令行中同時(shí)指定庫文件和腳本文件即可。
# gawk腳本名 test
BEGIN{ FS="\n"; RS=""}
{myprint()
}
然后執(zhí)行下述命令即可。(-f選項(xiàng)不能和內(nèi)聯(lián)gawk腳本一起使用,所以要在同一命令行中使用多個(gè) -f 選項(xiàng)。)?
gawk -f functionlib -f test test2.txt