shell腳本學(xué)習(xí)8-gawk

本節(jié)gawk是awk的gun版本,gawk實(shí)際上是一種編程語言而不是一個(gè)命令。gawk要用單引號和大括號包含進(jìn)來,把程序?qū)懙酱罄ㄌ柪锩妗?/p>

  1. gawk處理一行數(shù)據(jù)時(shí)的分隔符
    gawk會(huì)把一行數(shù)據(jù)按照任意的空白字符(比如空格或者制表符)進(jìn)行分割,0表示代表整行,1代表第一個(gè)數(shù)據(jù)段,以此類推。比如文件data的內(nèi)容為:
This is Fruit:apple
That is City:Beijing
These are books:maths
Those are animals:dogs

按照默認(rèn)的空白字符進(jìn)行分割,輸入:

gawk '{print $3}' data

運(yùn)行后結(jié)果為:

Fruit:apple
City:Beijing
books:maths
animals:dogs

如果想要修改分割符,比如以冒號作為分隔符,則輸入:

gawk -F: '{ print $2}' data

運(yùn)行后結(jié)果為:

apple
Beijing
maths
dogs
  1. gawk中使用多個(gè)指令
    gawk中使用多個(gè)指令的時(shí)候,除了最后一個(gè)指令外,每個(gè)指令的結(jié)尾都要加一個(gè)分號。比如輸入
gawk '{$1="This";print $0}' data

運(yùn)行后結(jié)果為:

This is Fruit:apple
This is City:Beijing
This are books:maths
This are animals:dogs
  1. 把指令放進(jìn)文件中,用gawk去加載文件
    比如建立一個(gè)文件gawk_file,內(nèi)容為:
{
str="-->"
print $1 str $2
}

輸入:

gawk -f gawk_file data

運(yùn)行后輸出:

This-->is
That-->is
These-->are
Those-->are

注意上面的gawk_file文件中去取str變量的值的時(shí)候并沒有用美元符號,而且指令與指令之間也不需要用分號。

  1. BEGIN關(guān)鍵字
    BEGIN關(guān)鍵字后面可以加語句,這些語句會(huì)在gawk讀取文件之前就執(zhí)行。比如輸入:
gawk 'BEGIN {print "Read file:..."} {print $0}' data

運(yùn)行結(jié)果為:

Read file:...
This is Fruit:apple
That is City:Beijing
These are books:maths
Those are animals:dogs
  1. END關(guān)鍵字
    END關(guān)鍵字后面可以加語句,這些語句會(huì)在gawk處理文件后再執(zhí)行。比如輸入:
gawk 'BEGIN {print "Read file:..."} {print $0} END{print "Done!"}' data

運(yùn)行后結(jié)果為:

Read file:...
This is Fruit:apple
That is City:Beijing
These are books:maths
Those are animals:dogs
Done!

可以把BEGIN,END等都寫到一個(gè)文件中去,比如建立一個(gè)文件gawk_file2,內(nèi)容為:

BEGIN {
print "Start"
print "Begin to read file"
FS=":"
}

{
print $0
}

END {
print "END"
}

輸入:

gawk -f gawk_file2 data

運(yùn)行后輸出結(jié)果為:

Start
Begin to read file
This is Fruit:apple
That is City:Beijing
These are books:maths
Those are animals:dogs
END
  1. 分隔符內(nèi)建變量
    內(nèi)建變量值得是shell中已經(jīng)定義過可以直接使用的變量,shell中用于分割作用的內(nèi)建變量有5個(gè),之前已經(jīng)提到過一個(gè)FS,F(xiàn)S是輸入字段的分隔符,除了FS還有FIELDWIDTH,OFS,RS,ORS。

6.1 OFS對輸出進(jìn)行分割
默認(rèn)情況下,對輸出進(jìn)行分割的是空格。當(dāng)然如果設(shè)置OFS的話那么就能修改風(fēng)格符了,比如輸入:

gawk 'BEGIN {FS=":";OFS="<--->"} {print $1,$2}' data

運(yùn)行后結(jié)果為:

This is Fruit<--->apple
That is City<--->Beijing
These are books<--->maths
Those are animals<--->dogs

如上所示,在BEGIN里面把輸入分隔符和輸出分隔符都設(shè)置號。

6.2 FIELDWIDTHS按寬度取出數(shù)據(jù)
FIELDWIDTHS設(shè)定之后,gawk根據(jù)輸入的數(shù)字在輸入的一行中去截取對應(yīng)的長度,同時(shí)FIELDWIDTHS設(shè)定之后FS就不起作用了。比如對于文本data的數(shù)據(jù)為:

This is Fruit:apple
That is City:Beijing
These are books:maths
Those are animals:dogs

輸入:

gawk 'BEGIN{FIELDWIDTHS="4 1 2 1 5 6";OFS="<--->"} {print $1,$3,$5,$6}' data

運(yùn)行后結(jié)果為:

This<--->is<--->Fruit<--->:apple
That<--->is<--->City:<--->Beijin
Thes<---> a<--->e boo<--->ks:mat
Thos<---> a<--->e ani<--->mals:d

6.3 RS作為輸入記錄的分隔符
默認(rèn)情況下,RS為換行符,也就說對于一個(gè)文本,每一行就是一個(gè)新的記錄。之前的比如1,2這種都是對一個(gè)記錄去處理的。有時(shí)候我們希望多行數(shù)據(jù)為一個(gè)記錄的時(shí)候,可以修改RS的值。比如有一個(gè)文本data2的內(nèi)容為:

Fan wei
China Beijing
Male
Actor

Ji Xiao Lan
Qing Beijing
Male
Guan

以上內(nèi)容實(shí)際上是兩段,現(xiàn)在想要把一段當(dāng)成一個(gè)整體,并且整段中的每一行當(dāng)做一個(gè)數(shù)據(jù)段。這里只要把FS設(shè)置為換行符\n,并把RS設(shè)置成空行。輸入如下:

gawk 'BEGIN{FS="\n"; RS=""} {print $1,$2}' data3

運(yùn)行后結(jié)果為:

Fan wei China Beijing
Ji Xiao Lan Qing Beijing

6.4 ORS作為輸出記錄的分隔符
同理,ORS作為輸出記錄的分隔符,默認(rèn)也是換行符\n。當(dāng)然也可以修改這個(gè)變量,輸入:

gawk 'BEGIN{FS="\n"; RS="";ORS="<>\n"} {print $1,$2}' data3

data3的內(nèi)容為:

Fan wei
China Beijing
Male
Actor

Ji Xiao Lan
Qing Beijing
Male
Guan

運(yùn)行后結(jié)果為:

Fan wei China Beijing<>
Ji Xiao Lan Qing Beijing<>
  1. 自定義變量
    gawk中也可以自己定義一些變量并使用,在使用變量的時(shí)候不需要加美元符號。比如在gawk中定義并打印字符串:
gawk 'BEGIN{str="Wu lin wai zhuan";print str}'

運(yùn)行后輸出結(jié)果為:

Wu lin wai zhuan

gawk中也可以使用數(shù)學(xué)運(yùn)算,如輸入:

gawk 'BEGIN{x=4;x=x*x+4;print x}'

運(yùn)行后結(jié)果為:

20
  1. gawk中使用字典
    gawk中能夠定義字典,類似于C++中的map一樣,比如輸入:
gawk 'BEGIN {city["JiangSu"]="NanJing";city["JiangXi"]="NanChang";print city["JiangSu"]}'

運(yùn)行后輸出結(jié)果為:

NanJing

當(dāng)然,也可以用數(shù)字,比如:

gawk 'BEGIN{array[1]=3;array[2]=5;multi=array[1]*array[2];print multi}'

運(yùn)行后輸出結(jié)果為:

15

同時(shí),也可以使用迭代語句來讀取字典中的值。gawk中使用for語句來取出字典中的數(shù)據(jù),不過每次取出的都是字典中key值。比如輸入:

gawk 'BEGIN{dict["a"]=1;dict["b"]=2;dict["c"]=3;dict["d"]=4;for (idx in dict){print "index", idx,"value",dict[idx]}}'

運(yùn)行后結(jié)果為:

index a value 1
index b value 2
index c value 3
index d value 4

注意index的返回值沒有規(guī)律,也就是說多次執(zhí)行的時(shí)候可能index返回的順序并不相同。同時(shí)也可以刪除字典中的一個(gè)對象,比如輸入:

gawk 'BEGIN{dict["a"]=1;dict["b"]=2;dict["c"]=3;dict["d"]=4;delete dict["d"];for (idx in dict){print "index", idx,"value",dict[idx]}}'

運(yùn)行后結(jié)果為:

index a value 1
index b value 2
index c value 3
  1. gawk中使用正則表達(dá)式
    gawk中可以使用正則表達(dá)式去匹配,當(dāng)然詳細(xì)的正則表達(dá)式的內(nèi)容這一節(jié)不展開。這里以文件data4為例,介紹如何使用正則表達(dá)式,data4的內(nèi)容為:
Vedio wulin is awesome
Apparently that is correct
which vulin

首先不用正則表達(dá)式,搜索匹配wulin這個(gè)單詞并把第一個(gè)字段打印出來,輸入:

gawk '/wulin/{print $1}' data4

運(yùn)行后結(jié)果為:

Vedio

這是因?yàn)閐ata4中的三行數(shù)據(jù)只有 第一行有wulin這個(gè)單詞?,F(xiàn)在使用正則表達(dá)式,輸入:

gawk '/[uvw]ulin/{print $1}' data4

運(yùn)行后結(jié)果為:

Vedio
which

因?yàn)閇uvw]這個(gè)表示屬于這三個(gè)字母的任何一個(gè)都匹配,所以第一行和第三行的wulin和vulin都匹配上了。

上面的正則表達(dá)式是使用文本的一整行去匹配,但是如果想要用一行中的某一個(gè)字段去匹配的話也可以的,這個(gè)時(shí)候要使用匹配操作符(波浪號~)。輸入:

gawk 'BEGIN{FS=":"} $1 ~ /^san/{print $1 $NF}' /etc/passw

運(yùn)行后結(jié)果為:

saned /bin/false

其對應(yīng)的原始數(shù)據(jù)為:

saned:x:119:127::/var/lib/saned:/bin/false

這個(gè)命令會(huì)在第一個(gè)字段中去判斷$1是不是以san開頭的單詞,如果是的話則打印第一個(gè)字段和最后一個(gè)字段。

如果想要排除這個(gè)正則表達(dá)式的關(guān)鍵字的時(shí)候則可以使用!,也就是說用!可以找出不匹配的行然后去處理,比如輸入

gawk 'BEGIN{FS=":"} $1 !~ /^san/{print $1, $NF}' /etc/passwd|grep san

運(yùn)行后結(jié)果中已經(jīng)沒有之前的saned的行了,但是/etc/passwd的其他行的數(shù)據(jù)都有。

  1. gawk中使用數(shù)字和字符串的比較
    對于數(shù)字的比較跟C語言的語法相同,有以下5種:
    a)數(shù)字x與數(shù)字y相等 ,x==y
    b)數(shù)字x大于數(shù)字y, x>y
    c)數(shù)字x大于等于數(shù)字y, x>=y
    d)數(shù)字x小于數(shù)字y, x<y
    e)數(shù)字x小于等于數(shù)字y, x<=y
    新建文件data5,內(nèi)容為:
100 madashuai xiaozhang
200 fandebiao chuzi
300 yufugui   cunzhang

輸入:

gawk '$1==200 {print $0}' data5

運(yùn)行后結(jié)果為:

200 fandebiao chuzi

再輸入:

gawk '$1<=200 {print $0}' data5

運(yùn)行后結(jié)果為:

100 madashuai xiaozhang
200 fandebiao chuzi

上面兩個(gè)輸入都是數(shù)字的比較,字符串同樣也可以比較,當(dāng)字符串完全相同的時(shí)候才能匹配,輸入:

gawk '$2=="fandebiao" {print $0}' data5

運(yùn)行后結(jié)果為:

200 fandebiao chuzi

再輸入:

gawk '$2=="fande" {print $0}' data5

運(yùn)行后結(jié)果為空,這說明必須要完全匹配才能處理。

  1. gawk中使用分支語句
    gawk中可以使用if-else這樣的分支語句,其語法與C語言的語法相同,比如data5的內(nèi)容為:
100 madashuai xiaozhang
200 fandebiao chuzi
300 yufugui   cunzhang

輸入:

gawk '{if ($1 ==300){x=$1;x=x*x;print x}}' data5

運(yùn)行后結(jié)果為:

90000

當(dāng)然,gawk中也可以使用else if和else語句,同樣和C語言的語法相同,輸入:

gawk '{if ($1==100) {print $1}else if($1 ==200 ){print $2} else {print $3}}' data5

運(yùn)行后結(jié)果為:

100
fandebiao
cunzhang
  1. gawk中使用while語句
    gawk中可以使用while循環(huán),語法與C語言相同,比如data6的內(nèi)容如下:
1 2 3 4
5 6 7 8
9 10 -3 -99

輸入:

gawk '{sum=0;i=1;while (i<=4){sum+=$i;i++;}avg=sum/3;print "average:",avg}' data6

運(yùn)行后結(jié)果為:

average: 3.33333
average: 8.66667
average: -27.6667

上面的命令是把每一行的四個(gè)數(shù)字求和除以3然后打印出來。同時(shí),gawk的while循環(huán)中也可以使用break和continue,輸入

gawk '{sum=0;i=1;while (i<=4){sum+=$i;if (i==2){break}i++;}avg=sum/3;print "average:",avg}' data6

運(yùn)行后結(jié)果為:

average: 1
average: 3.66667
average: 6.33333
  1. gawk中使用for語句
    gawk中使用for語句跟C語言相同,輸入的data6文件內(nèi)容為:
1 2 3 4
5 6 7 8
9 10 -3 -99

輸入如下命令:

gawk '{sum=0;for (i=1;i<=4;i++){sum+=$i;}avg=sum/3;print "average:",avg}' data6 

運(yùn)行后結(jié)果為:

average: 3.33333
average: 8.66667
average: -27.6667
  1. gawk中使用printf打印
    gawk中除了可以使用print語句外,還可以使用printf語句打印,用法和C語言相同。比如data7文本的內(nèi)容為:
312 3.145 great
666 45.01 good
899 0.004 nothing

輸入:

gawk '{printf "integer:%d,   float:%f,   string:%s\n",$1,$2,$3}' data7

運(yùn)行后結(jié)果為:

integer:312,   float:3.145000,   string:great
integer:666,   float:45.010000,   string:good
integer:899,   float:0.004000,   string:nothing
  1. gawk中使用內(nèi)建函數(shù)
    gawk中有一些內(nèi)建函數(shù)用于處理比較通用的運(yùn)算,比如數(shù)學(xué)運(yùn)算和字符串處理。
    14.1 gawk中使用數(shù)學(xué)運(yùn)算的內(nèi)建函數(shù)
    常用的數(shù)學(xué)運(yùn)算函數(shù)有sin,cos,sqrt,int等等,int是用于去整數(shù)值的運(yùn)算,輸入:
gawk 'BEGIN {y=int(3.14);z=int(-3.14);print y,z}'

運(yùn)行后結(jié)果為:

3 -3

14.2 gawk中使用字符串處理的函數(shù)
個(gè)人感覺這一節(jié)非常重要,之后可以用到的地方非常多。

14.2.1 toupper,tolower,length的使用
輸入文本data8的內(nèi)容為:

WuLinWaiZhuan,ZhaoBenShan

輸入:

 gawk 'BEGIN{FS=","}{x=$1;y=toupper(x);z=tolower(x);printf("%s,   %s,   %s,   %d\n"),x,y,z,length(z)}' data8

運(yùn)行后結(jié)果為:

WuLinWaiZhuan,   WULINWAIZHUAN,   wulinwaizhuan,   13

toupper和tolower函數(shù)將字符串分別轉(zhuǎn)化成大寫和小寫,length返回字符串的長度。

14.2.2 split函數(shù)分割字符串
split是按照指定的分割字符去分割字符串,返回值是分割后的字符串的個(gè)數(shù),輸入:

echo "12:34:56:78"|gawk '{split($0,a,":");for(i=1;i<=4;i++){print a[i]}}'

運(yùn)行后結(jié)果為:

12
34
56
78

當(dāng)在shell腳本中去對字符串引用時(shí)候,要使用"和"組成的雙引號。建立一個(gè)shell腳本,輸入:

#/bin/bash
str=12:34:56:78
awk 'BEGIN {num=split('"\"$str\""', array, ":");for (i=1;i<=num;i++){print array[i]}}'

運(yùn)行這個(gè)腳本后,結(jié)果為:

12
34
56
78

14.2.3 gawk中使用index函數(shù)
index(s,t)是查找字符串t在s字符串索引值,如果找不到返回0,index 返回子字符串第一次被匹配的位置,偏移量從位置1開始.輸入:

awk 'BEGIN { a="mytest";b="test";print index(a, b) }'

運(yùn)行后結(jié)果為:

3

再輸入:

awk 'BEGIN { a="mytest";b="ttt";print index(a, b) }'

運(yùn)行后結(jié)果為:

0

14.2.4 gawk中使用sub和gsub函數(shù)
sub和gsub都是用于字符串替換,sub只會(huì)替換一行中第一次的成功匹配,gsub會(huì)替換所有的成功匹配,比如文件data8的內(nèi)容為:

LinWaiZhuan,ZhaoBenShanLin

輸入:

gawk 'BEGIN{FS=","}{sub("Lin","Test");print $0}' data8

運(yùn)行后結(jié)果為:

TestWaiZhuan,ZhaoBenShanLin

sub函數(shù)只修改了第一個(gè)Lin為Test。
再輸入:

gawk 'BEGIN{FS=","}{gsub("Lin","Test");print $0}' data8

運(yùn)行后結(jié)果為:

TestWaiZhuan,ZhaoBenShanTest

gsub把所有的Lin都改成Test
注意:sub和gsub可以使用正則表達(dá)式,比如輸入:

gawk 'BEGIN{FS=","}{gsub("^Lin","Test");print $0}' data8

運(yùn)行后結(jié)果為:

TestWaiZhuan,ZhaoBenShanLin

這里用逗號把一行數(shù)據(jù)分割之后,修改以Lin開頭的字段。

14.2.5 substr函數(shù)截取字符串
substr(str, start,len)從字符串str的start索引位置截取len長度的字符串,如果么有指定len這個(gè)參數(shù)的話,那就截取到結(jié)尾。
輸入:

awk 'BEGIN { print substr( "hello world", 7,11 ) }'

運(yùn)行后結(jié)果為:

world

再輸入:

awk 'BEGIN { print substr( "hello world", 4 ) }'

運(yùn)行后結(jié)果為:

lo world

14.2.6 match函數(shù)正則表達(dá)式匹配
match 返回在字符串中正則表達(dá)式位置的索引,如果找不到指定的正則表達(dá)式則返回0。match函數(shù)會(huì)設(shè)置內(nèi)建變量RSTART為字符串中子字符串的開始位 置,RLENGTH為到子字符串末尾的字符個(gè)數(shù)。substr可利于這些變量來截取字符串
輸入:

awk 'BEGIN{start=match("this is a test",/[a-z]+$/); print start}'

運(yùn)行后結(jié)果為:

11

再輸入:

awk 'BEGIN{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'

運(yùn)行后結(jié)果為:

11 11 4
```gawk中使用數(shù)字和字符串的比較

15. 總結(jié)與展望
15.1 總結(jié)
a) gawk中對一行數(shù)據(jù)進(jìn)行分割的時(shí)候指定FS的值;
b) gawk中使用多個(gè)指令的時(shí)候用分號分割;
c) 把指令寫到文件中,用-f去加載文件;
d) BEGIN和END關(guān)鍵字使用;
e) 分隔符內(nèi)建變量的使用,F(xiàn)S,FIELDWIDTH,OFS,RS,ORS;
f) gawk中使用自定義變量不需要用美元符號;
g) gawk中使用字典;
h) gawk中使用正則表達(dá)式,!~不包含;
i)  gawk中使用數(shù)字和字符串的比較;
j)gawk中使用分支語句和循環(huán)語句(while,for);
k) gawk中使用printf打印
l)   gawk中使用內(nèi)建函數(shù)
15.2 展望
下一節(jié)學(xué)習(xí)shell腳本中的正則表達(dá)式,非常重要。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,679評論 0 4
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,716評論 0 5
  • 概要 64學(xué)時(shí) 3.5學(xué)分 章節(jié)安排 電子商務(wù)網(wǎng)站概況 HTML5+CSS3 JavaScript Node 電子...
    阿啊阿吖丁閱讀 9,851評論 0 3
  • ??引用類型的值(對象)是引用類型的一個(gè)實(shí)例。 ??在 ECMAscript 中,引用類型是一種數(shù)據(jù)結(jié)構(gòu),用于將數(shù)...
    霜天曉閱讀 1,219評論 0 1
  • 一、字符串在C#中,字符串是一系列不可修改的Unicode字符,創(chuàng)建字符串后,就不能修改它。要?jiǎng)?chuàng)建字符串,最常用的...
    CarlDonitz閱讀 1,386評論 0 2

友情鏈接更多精彩內(nèi)容