a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 學(xué)院 > 操作系統(tǒng) > 正文

GNU awk命令用法介紹

2024-06-28 16:04:48
字體:
供稿:網(wǎng)友

AWK簡介

AWK是一門解釋型的編程語言,它的名字來源于它的三位作者的姓氏:Alfred Aho,Peter Weinberger和Brian Kernighan。AWK能夠應(yīng)用于廣泛的計(jì)算和數(shù)據(jù)處理任務(wù)。所有的GNU/linux發(fā)行版都自帶GAWK,即GNU AWK,是AWK的擴(kuò)展并且與AWK完全兼容。

和上面講到的sed命令類似,AWK逐行讀取輸入流中的內(nèi)容,并對讀取的行執(zhí)行所有命令,如此循環(huán),直到輸入流結(jié)束。

本文基于GAWK進(jìn)行介紹,因?yàn)镚AWK比原生AWK使用更普遍些。

程序結(jié)構(gòu)

AWK命令格式如下:

awk [options] 'PRogram' input-file1 input-file2 ...

或者

awk [options] -f program-file input-file1 input-file2 ...

第一種格式中,awk從file中獲取輸入流,然后執(zhí)行單引號內(nèi)的程序。第二種格式則是從文件program-file中獲取將要執(zhí)行的程序。

上述AWK命令的program部分的結(jié)構(gòu)可分為三塊:BEGIN、BODY和END。

BEGIN:在AWK命令的一開始執(zhí)行的動作,它只執(zhí)行一次,可以把變量初始化放在這里。注意,BEGIN部分是可選的,并且一個(gè)AWK命令中可以有多個(gè)BEGIN塊。注意,如果有-v選項(xiàng)的賦值操作,則-v的操作在BEGIN之前。

BEGIN塊的寫法為:BEGIN{…}

BODY:程序主體,對輸入流的每一行執(zhí)行動作。如果存在BEGIN或END,則這部分是可選的。一個(gè)AWK命令中可以有多個(gè)BODY塊。

BODY塊的寫法為:{…}

END:在AWK命令的最后執(zhí)行的動作,它只執(zhí)行一次。注意,END部分是可選的,并且一個(gè)AWK命令中可以有多個(gè)END塊。注意,使用END { }塊時(shí),awk的file參數(shù)不能省略。

END塊的寫法為:END{…}

例如下面的命令:

[root@Ubuntu]awk_test:$ awk 'BEGIN{print "Output start!"}; {print}; END{print "Output done!"}' awk_test.txt Output start!USER       PID %MEM    VSZ   rss STAT START   TIME COMMANDroot         1  0.1   3652  1916 Ss   Jan07   0:03 /sbin/initroot         2  0.0      0     0 S    Jan07   0:00 [kthreadd]root         3  0.0      0     0 S    Jan07   0:02 [ksoftirqd/0]root        26  0.0      0     0 S    Jan07   0:40 [kswapd0]user       495  0.1   3588  1092 Ss   Jan07   0:00 /sbin/udevd --daemonuser       860  0.0   3584   908 S    Jan07   0:01 /sbin/udevd --daemonuser      1137  0.0   4520   776 S    Jan07   0:00 smbd -Fuser      1550  0.1   4521  1816 Ss   Jan07   0:15 nmbd -DOutput done!

可以看到這條命令在命令的開始打印一行輸出“Output start!”,然后對文件中的每一行內(nèi)容執(zhí)行print操作,最后又打印出一行輸出“Output done!”。

從句法結(jié)構(gòu)上來講,program由一條條規(guī)則組成,每條規(guī)則由模式動作組成,即模式匹配后執(zhí)行相應(yīng)的動作。動作放在花括號內(nèi)以與模式區(qū)分。所以,program一般的格式是這樣的:

pattern { action }

pattern { action }

那么,下面這條命令(打印長度大于80字符的行):

awk 'length($0) > 80' data

可以看到這條awk命令只有pattern而沒有action部分。如果沒有action部分,則執(zhí)行默認(rèn)動作:打印整個(gè)record。

也可以把program寫到文件里(不用加單引號),通過AWK的第二種格式來執(zhí)行。
[root@ubuntu]awk_test:$ cat progfile BEGIN{print "Output start!"};{print};END{print "Output done!"};[root@ubuntu]awk_test:$ awk –f progfile awk_test.txt

為了方便后期維護(hù),建議將AWK的程序文件以.awk作為后綴名。

另外,可以利用Shell的#!機(jī)制,將progfile內(nèi)容改為:
#!/usr/bin/awk –fBEGIN{print "Output start!"};{print};END{print "Output done!"};

這樣的話,執(zhí)行./progfile awk_test.txt即可。(通過type awk可以知道系統(tǒng)中awk命令的位置。)

注:使用#!機(jī)制的話,執(zhí)行的shell命令./progfile實(shí)際上是執(zhí)行:"#!后面的命令" +"./progfile腳本" + "./progfile腳本的參數(shù)"。另外,這種寫法,awk后面最多只能跟一個(gè)參數(shù);并且ARGV[0]的值在不同系統(tǒng)上可能表現(xiàn)不同,比如可能被解釋為awk或/usr/bin/awk或./progfile。

比較特別的,如果要在program內(nèi)使用或打印單引號,可以用其ASCII碼'/47'表示。或者把程序?qū)懺谖募校@樣就不用擔(dān)心單引號和program外圍的單引號混淆的問題。注意,在單引號中,反斜杠后接一個(gè)字符,會被解釋成這個(gè)字符的字面意思,即和不加反斜杠是一樣的含義。

你也可以通過下面兩種方法來打印單引號:

awk 'BEGIN { print "Here is a single quote <'"'"'>" }'

awk 'BEGIN { print "Here is a single quote<'/''>" }'

AWK選項(xiàng)

 -f program-file 執(zhí)行文件中的程序,前面已講過。

Program-file可以有多個(gè),通常用來將通用的代碼或函數(shù)做成庫,以實(shí)現(xiàn)代碼復(fù)用。

環(huán)境變量AWKPATH用來指定-f的搜索路徑,如果不指定AWKPATH,則默認(rèn)搜索“.:/usr/local/share/awk”,可以通過修改AWKPATH或ENVIRON["AWKPATH"]來修改搜索路徑,每個(gè)路徑之間用冒號隔開(.::都可以表示當(dāng)前路徑)。如果-f選項(xiàng)后面跟的是包含“/”的文件名,就不會去額外搜索路徑了。

 -v var=value 變量賦值,在BEGIN之前進(jìn)行。

例如,定義變量name,并賦值為“jason”:

[root@ubuntu]awk_test:$ awk -v name=jason 'BEGIN{printf("name=%s/n", name)}'name=jason

注意變量的引用不需要加“$”,實(shí)際上AWK的語法很多跟ANSI C的語法類似。“$”在AWK中是用來引用field的,后面會講到。

 -F fs 使用fs作為分隔符(默認(rèn)是空格)

例如,打印/etc/passwd文件中的用戶名一列:
[root@ubuntu]awk_test:$ cat /etc/passwd | awk -F ':' '{print $1}'rootdaemonbinsyssyncgames

 --compat 或 --traditional 使用原生awk,不會識別gawk的擴(kuò)展。例如,原生awk允許在while/for/do循環(huán)外面使用continue和break語句,這會被認(rèn)為和next語句意思相同。Gawk添加--traditional則可以使用這一特性。 --dump-variables[=file] 輸出排好序的AWK內(nèi)置的全局變量到文件(若不指定文件,則默認(rèn)為awkvars.out)

這個(gè)選項(xiàng)可以查看當(dāng)前可用的內(nèi)置全局變量。在編程的時(shí)候要注意,不要定義和這些內(nèi)置變量重名的變量。

 --non-decimal-data 識別輸入流中的十六進(jìn)制和八進(jìn)制

例如,將下面文件中的數(shù)字相加求和:
[root@ubuntu]awk_test:$ cat number.txt 0x120x3201210[root@ubuntu]awk_test:$ awk '{sum+=($1)}; END{print sum}' number.txt 22[root@ubuntu]awk_test:$ awk --non-decimal-data '{sum+=($1)}; END{print sum}' number.txt 88

可以看到,如果不加--non-decimal-data選項(xiàng),就只識別出十進(jìn)制的12和10。

不過man gawk中說“Use this option with great caution!”,一方面這個(gè)選項(xiàng)可能破壞舊的程序,另一方面這個(gè)選項(xiàng)可能在以后被摒棄。

 --profile[=prof_file] 生成awk命令的profile文件

這個(gè)選項(xiàng)以優(yōu)雅的格式將awk命令保存到文件,如果不指定文件名,則默認(rèn)為awkprof.out。
[root@ubuntu]awk_test:$ awk --non-decimal-data --profile '{sum+=($1)}; END{print sum}' number.txt[root@ubuntu]awk_test:$ cat awkprof.out 	# gawk profile, created Sun Jan  8 23:20:48 2017	# Rule(s)	{		sum += $1	}	# END block(s)	END {		print sum	}

如果使用pgawk執(zhí)行命令,則還會顯示每條語句以及每個(gè)函數(shù)的調(diào)用次數(shù)。

 --re-interval 在正則表達(dá)式中支持間隔表達(dá)式

傳統(tǒng)的awk不支持間隔表達(dá)式,必須加上--re-interval選項(xiàng)或者--posix選項(xiàng)才能使用。

 -e program-text --source program-text  program-text為awk的program源碼,這個(gè)選項(xiàng)允許將文件中的源碼和命令行中的源碼混合使用。在需要引用自定義的庫函數(shù)時(shí)就可以使用該選項(xiàng),例如:

awk -f func_test.awk --source 'BEGIN{printadd_INT(1,2)}' awk_test.txt

這個(gè)例子中,func_test.awk里面定義了函數(shù)add_INT(),這里將-f指定的文件程序和--source指定的命令行程序混合在了一起。

 -E file--exec file  意義和-f選項(xiàng)相同,不過有兩點(diǎn)區(qū)別:命令行中的其他選項(xiàng)都直接傳給awk,而awk先處理其他選項(xiàng)和參數(shù),最后才處理--exec選項(xiàng);另外,不允許“var=value”形式的變量賦值。

這個(gè)選項(xiàng)應(yīng)該在#!開頭的腳本里使用,例如:

#! /usr/local/bin/gawk -E awk program here …

這個(gè)選項(xiàng)可以防止向腳本里傳遞參數(shù),因?yàn)樗械膮?shù)都先被awk識別并處理了。

--include source-file--load ext

這兩個(gè)選項(xiàng)都是針對引用函數(shù)庫的,也可以在文件中使用@include和@load來引用庫文件。不過在我所用系統(tǒng)的gawk不支持這兩個(gè)參數(shù)以及相應(yīng)的AWKLIBPATH環(huán)境變量,我就不介紹了。我們就使用-f來引用庫文件吧,只是-f的文件里面可以是任何程序內(nèi)容,并不是只針對庫文件而設(shè)計(jì)的。

 -- 標(biāo)記選項(xiàng)的結(jié)束

這告訴awk選項(xiàng)部分已經(jīng)結(jié)束,可以用來傳遞以“-”開頭的參數(shù),而不被誤認(rèn)為是選項(xiàng)。

AWK的變量、Records和Fields

AWK的變量是動態(tài)生成的,在第一次被使用的時(shí)候開始存在。變量的值可以是下列數(shù)據(jù)類型:浮點(diǎn)型字符串類型一維數(shù)組。甚至一個(gè)變量既可以是浮點(diǎn)型也可以是字符串類型,這取決于代碼中如何使用它。

AWK會將“var=value”形式的參數(shù)認(rèn)為是變量賦值,例如下面這個(gè)命令,awk將“var=2”和“var=1”認(rèn)為是給var賦值,而不是一個(gè)文件名,這個(gè)過程在awk順序處理參數(shù)列表時(shí)進(jìn)行的。

awk 'var == 1 {print 1} var == 2 { print 2}'  var=2 awk_test2.txt var=1 awk_test1.txt

Records

一個(gè)record就是awk認(rèn)為的一行輸入,對一個(gè)輸入流,默認(rèn)以換行符分隔。不過可以通過內(nèi)置變量RS來修改。例如,把RS賦值為Jan07:

[root@ubuntu]awk_test:$ awk -v RS=Jan07 '{print}' awk_test.txt USER       PID %MEM    VSZ   RSS STAT START   TIME COMMANDroot         1  0.1   3652  1916 Ss      0:03 /sbin/initroot         2  0.0      0     0 S       0:00 [kthreadd]root         3  0.0      0     0 S       0:02 [ksoftirqd/0]root        26  0.0      0     0 S       0:40 [kswapd0]user       495  0.1   3588  1092 Ss      0:00 /sbin/udevd --daemonuser       860  0.0   3584   908 S       0:01 /sbin/udevd --daemonuser      1137  0.0   4520   776 S       0:00 smbd -Fuser      1550  0.1   4521  1816 Ss      0:15 nmbd -D

看效果就知道是什么意思了。注意“Jan07”本身沒有打印出來。

如果RS被賦值為單個(gè)字符,則這個(gè)字符就是records的分隔符;如果被賦值為多個(gè)字符,那RS實(shí)際上是一個(gè)正則表達(dá)式。

如果RS被賦值為空,則以空行作為record的分隔符。

fields

AWK會把一個(gè)record再分隔成一個(gè)個(gè)的field依次進(jìn)行處理,以變量FS的值作為分隔符。

如果FS被賦值為單個(gè)字符,則這個(gè)字符就是fields的分隔符;如果被賦值為多個(gè)字符,那就是一個(gè)正則表達(dá)式;如果FS是空,則record中的每個(gè)字符都是分隔符。

注意,如果FS是空格,則多個(gè)空格、tab和換行,都會被認(rèn)為是分隔符。

一個(gè)record中的各個(gè)field可以通過各自的位置來引用,依次為$1$2$3,...。而$0表示整個(gè)record。

如果給FIELDWIDTHS變量賦值為一個(gè)數(shù)值列表(以空格隔開),如下面的例子,record就會按照字符串長度來分隔fields而不是按照FS的值。這時(shí)FS變量會被忽略。

[root@ubuntu]awk_test:$ awk 'BEGIN{FIELDWIDTHS="2 4 4 4"}{print $1"||"$2"||"$3"||"$4}' awk_test.txt US||ER  ||    || PIDro||ot  ||    ||   1ro||ot  ||    ||   2ro||ot  ||    ||   3ro||ot  ||    ||  26us||er  ||    || 495us||er  ||    || 860us||er  ||    ||1137us||er  ||    ||1550

如果給FS重新賦值,就會切回到按照FS分隔fields。

NF變量用于獲取當(dāng)前record共分了多少了fields。你可以給NF、$0以及某個(gè)field賦值,那么相應(yīng)record會更新并重新劃分fields。例如:
[root@ubuntu]awk_test:$ awk '{NF-=1; if (FNR!=1) $1="json"; print}' awk_test.txt USER PID %MEM VSZ RSS STAT START TIMEjson 1 0.1 3652 1916 Ss Jan07 0:03json 2 0.0 0 0 S Jan07 0:00json 3 0.0 0 0 S Jan07 0:02json 26 0.0 0 0 S Jan07 0:40json 495 0.1 3588 1092 Ss Jan07 0:00 /sbin/udevdjson 860 0.0 3584 908 S Jan07 0:01 /sbin/udevdjson 1137 0.0 4520 776 S Jan07 0:00 smbdjson 1550 0.1 4521 1816 Ss Jan07 0:15 nmbd這個(gè)例子中,把NF減1,則原來的每個(gè)record的最后一個(gè)field就沒有打印出來。FNR表示當(dāng)前已經(jīng)輸入了幾個(gè)record,例子中將文件除了第一行之外的第一個(gè)field的值都改成了“jason”。

內(nèi)置變量

AWK有一些內(nèi)置的全局變量可以直接使用,會使編程更方便。

內(nèi)置變量

含義

ARGC

Awk命令行的參數(shù)個(gè)數(shù)(不包括選項(xiàng)和選項(xiàng)的值以及program部分),awk自身是第0個(gè)參數(shù)。

ARGV

Awk的參數(shù)列表,共ARGC個(gè)元素。

ARGIND

當(dāng)前正在處理的文件處于ARGV數(shù)組中的index。

BINMODE

是否使用binmode打開文件。1("r"),2("w"),3("rw")分別表示輸入文件、輸出文件、所有文件需要使用binmode打開。

CONVFMT

數(shù)字的格式化類型,默認(rèn)是"%.6g"。

ENVIRON

保存當(dāng)前所有環(huán)境變量的數(shù)組。這個(gè)數(shù)組是以環(huán)境變量名作為下標(biāo)的,例如ENVIRON["HOME"]的值是"/root"。

ERRNO

當(dāng)getline或close失敗,ERRNO會保存字符串形式的錯(cuò)誤描述。

FIELDWIDTHS

一個(gè)以空格分隔的數(shù)值列表,設(shè)置這個(gè)值后,F(xiàn)S失效,record改以字符長度來劃分fields。

FILENAME

Awk當(dāng)前處理的文件的名字。注意,在BEGIN{ }中由于還沒開始處理文件,F(xiàn)ILENAME是空(除非被getline設(shè)置)。

FNR

表示正在處理的文件目前已經(jīng)輸入了幾個(gè)record。

FS

Field分隔符,默認(rèn)是空格。

IGNORECASE

是否忽略大小寫,默認(rèn)是0。用于控制正則表達(dá)式和字符串操作,例如會影響records和fields的分隔符。注意,數(shù)組下標(biāo)不受影響。

LINT

如果為true,則對可能不兼容的awk命令提示warning,如果為fatal,則提示為錯(cuò)誤。默認(rèn)是0:不提示。

NF

當(dāng)前record中的fields的數(shù)目。

NR

已經(jīng)處理的record的數(shù)目(包括當(dāng)前record)。

OFMT

輸出中數(shù)字的格式,默認(rèn)是“%.6g”。

OFS

輸出中fields的分隔符,默認(rèn)是空格。例如下面的命令,就會以” : ”來打印fields(注意$1 $2 $3之間要加逗號):

awk -v OFS=" : " '{print $1,$2,$3}' awk_test.txt

ORS

輸出中records的分隔符,默認(rèn)是新行。

PROCINFO

一個(gè)包含正在執(zhí)行的awk命令自身信息的數(shù)組,以元素名作為下標(biāo),例如PROCINFO[“egid”],PROCINFO[“pid”]等,下面的命令可以列舉所有的元素:

awk '{for (var in PROCINFO) print var;}' awk_test.txt

RS

records分隔符,默認(rèn)是新行。

RT

record的結(jié)束符,通常被賦值為RS。

RSTART

match()匹配成功的子串的第一個(gè)字符在原始字符串中的index(從1開始)。0表示匹配失敗。

RLENGTH

match()匹配成功的子串的長度。-1表示匹配失敗(可以匹配空串,此時(shí)長度為0)。

SUBSEP

數(shù)組下標(biāo)分隔符,默認(rèn)為/034即0x1C的ASCII符號。在訪問多維數(shù)組時(shí)有用。

TEXTDOMAIN

文本域,本地化的時(shí)候用到。

對于FS,強(qiáng)調(diào)一個(gè)‘FS =" "’和‘FS = "[ /t/n]+"’的不同,這兩種FS都是將多個(gè)空格、tab或newline作為分隔符。但是前者會先將record中的前導(dǎo)空格和尾部空格剝掉,再決定如何分割fields。例如下面兩條命令的結(jié)果就不同:

[root@ubuntu]awk_test:$ echo ' a b c d ' | awk '{ print $2 }'b[root@ubuntu]awk_test:$ echo ' a b c d ' | awk 'BEGIN { FS = "[ /t/n]+" }{ print $2 }'A也可以據(jù)此特征來刪除前導(dǎo)空格:
[root@ubuntu]awk_test:$ echo '   a b c d' | awk '{ print; $2 = $2; print }'   a b c da b c d

這條命令通過$2=$2,讓awk重新劃分fields,由于FS模式是空格,這時(shí)就會先把前導(dǎo)空格和尾部空格剝掉。

數(shù)組

AWK中的數(shù)組是關(guān)聯(lián)數(shù)組(鍵值對的形式),數(shù)組下標(biāo)放在方括號“[ ]”內(nèi),數(shù)組下標(biāo)可以是數(shù)值或字符串。可以用(expr, expr ...)來模擬多維數(shù)組的下標(biāo)。例如:

i = "A"; j = "B"; k = "C"x[i, j, k] = "hello, world/n"

上面定義了數(shù)組x下標(biāo)為"A/034B/034C"的值為"hello,world/n"。

操作符“in”可以用來測試下標(biāo)是否存在,例如:

if (val in array)print array[val]

如果是多維的下標(biāo),則寫成 if ((i, j) in array) print array[i, j]

也可以用“in”來遍歷數(shù)組:

下面兩個(gè)例子,前者定義了一個(gè)一維數(shù)組,數(shù)組下標(biāo)是[“a,b”]的元素。后者用來定義多維數(shù)組,例子中定義了三維數(shù)組中下標(biāo)為[”a”][“,”][”b”]的元素。
[root@ubuntu]awk_test:$ awk 'BEGIN{array["a"",""b"]=1;for(i in array) print i}'a,b[root@ubuntu]awk_test:$ awk 'BEGIN{array["a",",","b"]=1;for(i in array) print i}'a/034,/034b

記住,數(shù)組的小標(biāo)總是字符串,如果以數(shù)值為下標(biāo),也會轉(zhuǎn)換成字符串,也就是說,a[17]的下標(biāo)是"17",并且和a[021]、a[0x11]是相同的下標(biāo)。

使用delete可以刪除一個(gè)數(shù)組元素,例如delete array[1],也可以delete array來刪除整個(gè)數(shù)組。

變量類型轉(zhuǎn)換

變量和fields可以是字符串或浮點(diǎn)數(shù)類型,一個(gè)變量和field的值是什么類型依賴于它處于的上下文,例如,如果用于數(shù)學(xué)表達(dá)式,就被當(dāng)為數(shù)值類型。

如果需要強(qiáng)制變量或field被當(dāng)作數(shù)值,則寫成var+0。如果需要強(qiáng)制被當(dāng)作字符串,則連接一個(gè)空串,例如var ""

雖然所有的數(shù)值都是浮點(diǎn)型的,但是對于一個(gè)整數(shù),轉(zhuǎn)換成字符串的結(jié)果就是整型,例如12會被轉(zhuǎn)換為“12”而不是“12.00”。

在比較兩個(gè)變量var1和var2時(shí),如果兩個(gè)變量都是浮點(diǎn)型,則按照數(shù)值來比較;如果一個(gè)浮點(diǎn)型,另一個(gè)是字符串,則按照數(shù)值來比較,這時(shí),字符串變量被當(dāng)做“數(shù)值字符串”,例如("12"==12)的值為1;如果兩個(gè)變量都是字符串,則按照字符串來比較。

注意,只有在處理用戶輸入時(shí),才會將形如“57”這種看起來像數(shù)值的字符串認(rèn)為是“數(shù)值字符串”,例如getline的輸入、FILENAME、ARGV的成員、ENVIRON的成員以及split()產(chǎn)生的數(shù)組元素。其他情況下,則只是一個(gè)字符串常量。

未初始化的變量,會有兩個(gè)默認(rèn)的初始值:數(shù)值0以及空字符串""。

八進(jìn)制和十六進(jìn)制

gawk識別八進(jìn)制和十六進(jìn)制,例如011、0x16。

字符串常量

字符串常量是指雙引號內(nèi)的字符序列。在字符串中,可以包含轉(zhuǎn)義字符,如下:

轉(zhuǎn)義字符

含義

//

字面含義的反斜杠

/a

“alert”字符,通常是ASCII中的BEL

/b

backspace,回車

/f

form-feed,換頁符

/n

newline,換行符

/r

carriage return,回車

/t

horizontal tab

/v

vertical tab

/xhex

十六進(jìn)制數(shù)表示的ASCII碼字符。例如/x2A表示ASCII中的“*”號

/ddd

一個(gè)、兩個(gè)或三個(gè)數(shù)字組成的八進(jìn)制數(shù)值表示的ASCII碼字符。例如/052表示ASCII中的“*”號,注意/52同/052相同

/c

字面含義的字符c,例如需要使用原意的*號,則需要寫成/*。

轉(zhuǎn)義字符也可以用在正則表達(dá)式中,例如/[ /t/f/n/r/v]/表示匹配空白字符,/a/52b/同/a/*b/。

模式和動作

AWK是一個(gè)line-oriented的語言,對每一行(record),先進(jìn)行模式匹配,再執(zhí)行動作。動作的語句放在花括號{ }里面。如果模式為空,則對所有record執(zhí)行動作,例如 { print } ,就是無條件的打印整個(gè)record。

用“#”對一行程序進(jìn)行注釋,直到換行則注釋內(nèi)容結(jié)束。

正常情況下,一個(gè)完整的語句以換行結(jié)束,但一個(gè)語句也可以寫成多行,如果一個(gè)語句在“,”、“{”、“?”、“:”、“&&”“||”處換行,則認(rèn)為該語句尚未完成;一個(gè)語句在一行中以do或else結(jié)尾,也會認(rèn)為該語句未完成而繼續(xù)讀取下一行;其他情況下,可以在行末添加“/”來標(biāo)記這一行尚未結(jié)束(建議不要在pattern或字符串以及注釋的中間用反斜杠換行)。

也可以將多個(gè)語句寫到一行中,語句之間用分號“;”隔開。

模式(patterns)

AWK的模式可以是下面的其中一種:

  BEGIN  END  /regular expression/  relational expression  pattern && pattern  pattern || pattern  pattern ? pattern : pattern  (pattern)  ! pattern  pattern1, pattern2

BEGINEND是兩個(gè)比較特殊的模式,他們不對輸入做模式匹配,因?yàn)锽EGIN和END分別是在處理輸入之前和之后。多個(gè)BEGIN塊會被merge成一個(gè)BEGIN塊,這個(gè)BEGIN里面的語句會在開始讀取輸入之前執(zhí)行;多個(gè)END塊會被merge成一個(gè)END塊,這個(gè)END里面的語句會在處理完所有輸入之后執(zhí)行(或者執(zhí)行exit)。注意, BEGIN和END必須是獨(dú)立的,不能糅合在其他pattern表達(dá)式中。并且BEGIN和END不能沒有action部分,也就是說BEGIN和END后面不能沒有花括號{ }。

對于/regular expression/模式,會對所有匹配到該正則表達(dá)式的record執(zhí)行其關(guān)聯(lián)的語句。例如,打印包含“root”的行:

awk '/root/ {print $0}' awk_test.txt

一個(gè)relationalexpression可以使用后面將要講到的任何運(yùn)算符,這種模式通常用來測試一個(gè)field是否匹配某個(gè)正則表達(dá)式。關(guān)系表達(dá)式是指使用關(guān)系運(yùn)算符(>,>=,<,<=,==,!=)連接一個(gè)或兩個(gè)表達(dá)式組成的式子。

“&&”、“||”和“!”即我們熟知的與、或、非邏輯運(yùn)算符,可以用來將多個(gè)patterns連接在一起,這時(shí)他們是short-circuite valuation(短路求值)的,例如對于&&操作,只要第一個(gè)值是false,那整個(gè)表達(dá)式就是false,就沒必要計(jì)算后續(xù)的值了。圓括號( )可以改變運(yùn)算符的運(yùn)算順序。

例如,打印第一個(gè)field不是“root”的行且第三個(gè)field等于“0.0”的行:
awk '$1 != "root" && $3 == "0.0" {print}' awk_test.txt

“?:”運(yùn)算符和C語言中的三目的條件運(yùn)算符一樣,pattern1為true則選用pattern2,否則選用pattern3。

pattern1, pattern2形式的表達(dá)式被稱為范圍樣式,它將匹配pattern1的record,匹配pattern2的record以及這兩個(gè)record之間的所有record都匹配出來。

正則表達(dá)式

正則表達(dá)式由下表中一系列的字符集合組成。注:其中c表示character,r表示regular expression。

字符

含義

c

匹配非元字符c

/c

匹配元字符c的字面含義。由于元字符有特殊含義,因此必須加反斜杠來匹配其原始的字符含義。這些字符包括"["、"]"、"/"、"^"、"$"、"."、"|"、"?"、"*"、"+"、"{"、"}"、"("、")"等。

.

匹配一個(gè)字符(包括換行)

^

匹配字符串的開頭

$

匹配字符串的結(jié)尾(我系統(tǒng)上不支持)

[abc...]

匹配字符列表abc…中的任何一個(gè)字符

[^abc...]

匹配字符列表abc…之外的任何一個(gè)字符

r1|r2

匹配r1或r2

r1r2

匹配r1且其后緊跟r2

r+

匹配一個(gè)或多個(gè)r

r*

匹配0個(gè)或多個(gè)r

r?

匹配0個(gè)或1個(gè)r

(r)

分組,匹配圓括號中的所有字符組合r

r{n}

r{n,}

r{n,m}

花括號內(nèi)有1個(gè)或2個(gè)數(shù)值被稱為區(qū)間表達(dá)式:只有一個(gè)數(shù)字n,則表示前面的正則表達(dá)式r重復(fù)n次;有一個(gè)數(shù)字n和一個(gè)逗號,表示r至少重復(fù)n次;有兩個(gè)數(shù)字n和m,表示r重復(fù)n到m次。

區(qū)間表達(dá)式只有在指定--posix或--re-interval的時(shí)候才可用。

/y

匹配一個(gè)單詞開頭和結(jié)尾的空串,例如‘/yballs?/y’匹配‘ball’或‘balls’,但不匹配‘football’

/B

和/y相反

/s

匹配空白字符,同[[:space:]]

/S

匹配非空白字符,同[^[:space:]]

/<

匹配一個(gè)單詞開頭的空串,例如//<away/匹配‘a(chǎn)way’但不匹配‘stowaway’

/>

匹配一個(gè)單詞結(jié)尾的空串

/w

匹配Word-constituent的字符(包括字母、數(shù)字和下劃線),同‘[[:alnum:]_]’

/W

匹配非word-constituent的字符,同‘[^[:alnum:]_]’

/`

匹配一個(gè)buffer(字符串)開頭的空串,同^

/'

匹配一個(gè)buffer結(jié)尾的空串,同$

上表中紅色標(biāo)記的字符用于連接多個(gè)正則表達(dá)式,我們稱之為“正則表達(dá)式運(yùn)算符”或“元字符”。

在字符串常量中有效的轉(zhuǎn)義字符,在正則表達(dá)式中同樣有效。

正則表達(dá)式通常用兩個(gè)斜杠“/ /”包裹起來作為pattern使用,我們稱之為正則表達(dá)式常量。

在中括號表達(dá)式中引用‘/’、‘] ’、‘-’或‘^’,需要加反斜杠,例如“[d/]]”匹配字符'd'或字符']'。

正則表達(dá)式的匹配遵循最左開始最長的匹配的原則,例如下面表達(dá)式的結(jié)果是"<A>bcd":

echo aaaabcd | awk '{ sub(/a+/, "<A>"); print }'

字符類是POSIX標(biāo)準(zhǔn)中引入的特性,一個(gè)字符類表示了某個(gè)特定屬性的字符的集合。POSIX標(biāo)準(zhǔn)定義的字符類包括:

字符類

含義

[:alnum:]

字母或數(shù)字

[:alpha:]

字母

[:blank:]

空格或tab

[:cntrl:]

控制字符

[:digit:]

數(shù)字

[:graph:]

可打印且可見的字符(例如space可打印但不可見,而字符a既可打印又可見)

[:lower:]

小寫字母

[:print:]

可打印的字符(非控制字符)

[:punct:]

標(biāo)點(diǎn)符號(非字母、數(shù)字、控制字符和空白字符)

[:space:]

空白字符(例如空格、tab、換頁符等等)

[:upper:]

大寫字母

[:xdigit:]

十六進(jìn)制數(shù)字

字符類在使用時(shí)必須放在正則表達(dá)式的方括號[ ]里面,例如要匹配包含字母’n’或者數(shù)字的record,可以這樣寫:

[root@ubuntu]awk_test:$ awk '/[n[:digit:]]/' regexp.txt

我們有時(shí)將匹配字母和數(shù)字寫成/[A-Za-z0-9]/,但在本地化的時(shí)候,一些國家的字母表的字符集并不是這些字符,這時(shí)我們使用/[[:alnum:]]/就可以準(zhǔn)確的匹配而不必?fù)?dān)心本地化后的差異。

還有兩個(gè)特殊的字符序列:Collating Symbols和Equivalence Classes,應(yīng)用在非英語國家的本地化,例如用一個(gè)字符來表示多個(gè)字符/[[.ch.]]/或者定義多個(gè)等價(jià)字符/[[=e=]]/,有興趣的可以自己查閱相關(guān)資料。

注意,/y,/B,/s,/S,/<,/>,/w,/W,/`和/'這些正則表達(dá)式的運(yùn)算符是gawk特有的,gawk的不同選項(xiàng)可能影響如何解析正則表達(dá)式:

無選項(xiàng):上述所有運(yùn)算符均有效(區(qū)間表達(dá)式除外)。

--posix:只支持POSIX標(biāo)準(zhǔn)(包括區(qū)間表達(dá)式)的,那么/w就只表示字面意思的'w'。

--traditional:只支持傳統(tǒng)的UNIX awk的正則表達(dá)式,此時(shí),GNU的運(yùn)算符、區(qū)間表達(dá)式、字符類都不支持,八進(jìn)制和十六進(jìn)制的轉(zhuǎn)義字符("/ddd","/xhex")也會按字面意思解析。

--re-interval:支持區(qū)間表達(dá)式(即使有--traditional選項(xiàng))。

我們可以通過將IGNORECASE設(shè)置為一個(gè)非0的值,使AWK在匹配時(shí)忽略大小寫。也可以用toupper()/tolower()或中括號表達(dá)式,來只對某一些規(guī)則忽略大小寫。

動作(actions)

AWK中的動作語句(action statements)都放在花括號{ }中,由大部分語言都有的賦值、條件和循環(huán)語句組成。AWK中的運(yùn)算符、控制語句以及輸入輸出語句都是仿照C語言來定義的。

運(yùn)算符

AWK中運(yùn)算符按照優(yōu)先級由高到低,列舉如下:

運(yùn)算符

含義

(…)

分組

$

field引用

++  --

自增、自減,均可前置和后置

^

冪運(yùn)算(也可以用**,對應(yīng)的冪運(yùn)算賦值**=)

+  -  !

一元運(yùn)算符的+、-、邏輯非

*  /  %

乘、除、取模

+  -

加、減

space

字符串連接

|  |&

管道IO、協(xié)同進(jìn)程的管道IO。getline,print和printf使用

<  >  <=  >=  

!=  ==

關(guān)系運(yùn)算符

~  !~

正則表達(dá)式的匹配、不匹配,一般用法是/exp/ ~ /regexp/,其中右側(cè)可以是任何表達(dá)式(不需要必須是正則表達(dá)式常量)。例如$0 ~ /foo/意為查找匹配foo的$0,若匹配,則返回1,不匹配返回0。

in

獲取數(shù)組成員

&&

邏輯與

||

邏輯或

?:

條件表達(dá)式,格式為expr1 ? expr2 : expr3,如果expr1為true,則表達(dá)式的值為expr2,否則為expr3

=  +=  -=  *= 

/=  %=  ^=

賦值運(yùn)算符,均支持a=a+b和a+=b這兩種形式。

控制語句

控制語句列舉如下:

  if (condition) statement [ elsestatement ]  while (condition) statement  do statement while (condition)  for (initialization; condition; increment) statement  for (var in array) statement  switch (expression) {case value or regular expression:   case-bodydefault:   default-body}  break  continue  delete array[index]  delete array  exit [ expression ]  { statements }

這些控制語句和ANSI C中類似語句的語法相同。Switch的每個(gè)case分支通常要添加break語句以保證唯一匹配。

I/O語句

輸入輸出語句列舉如下:

               I/O statement                                                      

解釋

close(file [, how])

關(guān)閉文件、管道或協(xié)同進(jìn)程。參數(shù)“how”只有在關(guān)閉協(xié)同進(jìn)程的雙向管道其中一端時(shí)才會用到,是字符串類型,可取"to"或"from"。

getline

把$0賦值為下一個(gè)輸入的record。同時(shí)會更新NF、NR和FNR。

getline <file

把$0賦值為文件file的下一個(gè)record。同時(shí)會更新NF。

getline var

把變量var賦值為下一個(gè)輸入的record。同時(shí)會更新NR和FNR。

getline var <file

把變量var賦值為文件file的下一個(gè)record。

command | getline [var]

執(zhí)行command并將輸出作為getline或getline var的輸入。

command |& getline [var]

執(zhí)行協(xié)同進(jìn)程command并將輸出作為getline或getline var的輸入。(協(xié)同進(jìn)程是gawk的擴(kuò)展,command也可以是一個(gè)socket)

next

停止處理當(dāng)前的record,并讀取下一個(gè)record,然后重新從awk程序中第一個(gè)pattern開始處理新的record。如果當(dāng)前已經(jīng)達(dá)到輸入數(shù)據(jù)中最后一個(gè)record,則開始執(zhí)行END{ }程序塊。

nextfile

停止處理當(dāng)前的文件,并從下一個(gè)文件中讀取record,然后重新從awk程序中第一個(gè)pattern開始處理新的record。FILENAME和ARGIND參數(shù)會被更新,F(xiàn)NR被重置為1。如果當(dāng)前已經(jīng)達(dá)到輸入數(shù)據(jù)中最后一個(gè)record,則開始執(zhí)行END{ }程序塊。

print

打印當(dāng)前的record(根據(jù)ORS的值判斷record是否輸出完畢)。

print expr-list

打印表達(dá)式列表。如果有多個(gè)表達(dá)式,每個(gè)表達(dá)式之間用OFS分隔。(根據(jù)ORS的值判斷record是否輸出完畢)

print expr-list >file

打印表達(dá)式列表到文件。如果有多個(gè)表達(dá)式,每個(gè)表達(dá)式之間用OFS分隔。(根據(jù)ORS的值判斷record是否輸出完畢)

printf fmt, expr-list

格式化的打印

printf fmt, expr-list >file

格式化的打印到文件。例如:

awk 'BEGIN{printf "%#x", 10 >"getnum.txt"}'

system(cmd-line)

執(zhí)行命令cmd-line,并將exit status作為返回值。例如:

system("uname –a")

fflush([file])

清空已打開的輸出文件或管道文件的所有緩存。如果不帶file參數(shù),則清空標(biāo)準(zhǔn)輸出,如果file參數(shù)為null string,則所有打開的輸出文件和管道的緩存都會被清空。

另外,print和printf也允許以下形式的輸出重定向:

print ... >> file

將輸出追加到文件file

print ... | command

向管道寫內(nèi)容

print ... |& command

向協(xié)同進(jìn)程或socket發(fā)送數(shù)據(jù)

getline命令執(zhí)行成功返回1,到達(dá)文件結(jié)尾返回0,出錯(cuò)返回-1。如果出錯(cuò),則字符串ERRNO包含了出錯(cuò)信息。

注意,如果在打開一個(gè)雙向(two-way)socket的時(shí)候失敗,將會返回一個(gè)非致命的錯(cuò)誤到調(diào)用者。

如果在一個(gè)循環(huán)中使用管道、協(xié)同進(jìn)程或socket(向getline輸出或從print/printf輸入),你必須使用close()來創(chuàng)建新的command或socket的實(shí)例。AWK在管道、協(xié)同進(jìn)程或socket返回EOF的時(shí)候不會自動關(guān)閉它們。

printf語句

AWK里的printf語句和sprintf()函數(shù)支持如下的標(biāo)準(zhǔn)格式轉(zhuǎn)換符:

格式符

含義

%c

一個(gè)ASCII字符。如果傳入的參數(shù)是一個(gè)數(shù)值,則將其轉(zhuǎn)換為字符并打印;否則,認(rèn)為傳入的參數(shù)是字符串,只打印該字符串的第一個(gè)字符。

%d, %i

十進(jìn)制數(shù)字(整數(shù)部分)

%e, %E

將一個(gè)浮點(diǎn)數(shù)以“[-]d.dddddde[+-]dd”的形式打印。%E使用大寫的E。

%f, %F

將一個(gè)浮點(diǎn)數(shù)以“[-]ddd.dddddd”的形式打印。使用%F(需要系統(tǒng)庫支持),則以大寫字母顯示"not a number"和"infinity"這類的值。

%g, %G

根據(jù)實(shí)際情況轉(zhuǎn)換為%e或%f,選擇其中最簡短的格式。%G對應(yīng)%E。

%o

無符號的八進(jìn)制整數(shù)。

%u

無符號的十進(jìn)制整數(shù)。

%s

字符串。

%x, %X

無符號的十六進(jìn)制整數(shù)。

%%

字符'%'的原意(不會取實(shí)參)。

在這些格式符中,'%'和控制字符之間可以放置如下的額外參數(shù)(和C語言中printf的格式符用法相同):

count$

位置說明符,指定對第count個(gè)參數(shù)進(jìn)行格式化轉(zhuǎn)換。例如:printf("%2$d/n", 23, 24);打印的值是24。

width

指定格式化后的最短打印長度,如果不夠長則填充空格,默認(rèn)右對齊。

-

左對齊,通常與width搭配使用。

0

上述不足width的話,使用前導(dǎo)0填充而不是空格。只對數(shù)值類型有效。

+

對數(shù)值添加正負(fù)號。只對數(shù)值類型有效。

#

以另一種形式打印格式化的內(nèi)容:例如%#o會在數(shù)值前面填0;%#x、%#X會在數(shù)值前面填0x或0X;對%#e、%#E、%#f和%#F,結(jié)果總會有小數(shù)點(diǎn);%#g、%#G總會顯示小數(shù)部分。

space

對正數(shù),前面填一個(gè)空格;對負(fù)數(shù),前面填負(fù)號。

.prec

對%e、%E、%f和%F,指明小數(shù)部分的最大位數(shù);對%g、%G,指明有效數(shù)字的最大長度;對%d、%o、%i、%u、%x和%X,和面前的0width一樣,指明最短打印長度,不足則前面補(bǔ)0;對%s,指明最長打印的字符數(shù)。

另外,printf和sprintf()支持動態(tài)的width和.prec:可以從參數(shù)列表中的值作為width或.prec的值。通過在count$前面加一個(gè)*號來達(dá)到這種效果。例如:

printf("%1$*2$s/n", "Bye bye!", 12);這個(gè)例子中,1$仍然是位置說明符的作用,而*2$的意思是將第二個(gè)參數(shù)替換在這個(gè)位置,這個(gè)語句就變成了:
printf("%1$12s/n", "Bye bye!", 12);

特殊文件

在通過print、printf、getline進(jìn)行I/O重定向時(shí),gawk可識別一些特定的文件名,并且支持從gawk的父進(jìn)程(通常是shell)中繼承這些文件的文件描述符來進(jìn)行文件操作。同時(shí),這些文件也可以用作命令行中的數(shù)據(jù)文件名。這些文件為:

/dev/stdin    標(biāo)準(zhǔn)輸入

/dev/stdout  標(biāo)準(zhǔn)輸出

/dev/stderr   標(biāo)準(zhǔn)錯(cuò)誤輸出

/dev/fd/n      與文件描述符n關(guān)聯(lián)的文件

另外,使用破折號“-”也可以引用標(biāo)準(zhǔn)輸入,例如:

some_command | awk -f myprog.awk file1 - file2

這條命令中,awk會先讀取file1,然后讀取some_command的輸出,然后讀取file2。

下面三個(gè)特殊的文件名,可以與協(xié)同進(jìn)程操作符“|&”配合使用,創(chuàng)建TCP/ip網(wǎng)絡(luò)連接。

/inet/tcp/lport/rhost/rport              本地端口是lport,與遠(yuǎn)程主機(jī)rhost、遠(yuǎn)程端口rport的TCP/IP連接,如果端口為0,則讓系統(tǒng)自己選擇端口。

/inet/udp/lport/rhost/rport      同上,只是TCP改為UDP。

/inet/raw/lport/rhost/rport             未使用,供后續(xù)擴(kuò)展。

下面這些文件名用來獲取當(dāng)前正在運(yùn)行的gawk進(jìn)程的信息:/dev/pid,/dev/ppid,/dev/pgrpid和/dev/user。目前已被棄用,改為使用PROCINFO獲取進(jìn)程信息。

數(shù)值操作函數(shù)

AWK提供以下一些內(nèi)置的算術(shù)函數(shù):

函數(shù)

作用

atan2(y, x)

求y/x的反正切,單位是弧度。

cos(expr)

求余弦,expr的單位是弧度。

exp(expr)

求指數(shù)。

int(expr)

截?cái)鄀xpr保留整數(shù)部分。

log(expr)

求自然對數(shù)。

rand()

生成一個(gè)隨機(jī)數(shù)N,0 ≤ N < 1。

sin(expr)

求正弦,expr的單位是弧度。

sqrt(expr)

求平方根。

srand([expr])

為隨機(jī)數(shù)生成器指定一個(gè)新種子expr。如果不指定expr,就使用時(shí)間作為種子。函數(shù)的返回值是之前的種子。

字符串函數(shù)

Gawk提供以下內(nèi)置的字符串函數(shù):

              函數(shù)                                

作用

asort(s [, d])

給數(shù)組s中的成員排序(按照gawk默認(rèn)的升序排序方法),排序完成后,s的數(shù)組下標(biāo)改為從1開始的整數(shù)序列。

如果指定第二個(gè)參數(shù)d,則排序的結(jié)果放在數(shù)組d中,原數(shù)組s不變化。

函數(shù)的返回值是原數(shù)組s的元素個(gè)數(shù)。

asorti(s [, d])

給數(shù)組s的下標(biāo)排序,(按照gawk默認(rèn)的升序排序方法),排序完成后,s的數(shù)組下標(biāo)改為從1開始的整數(shù)序列,而原來的下標(biāo)改為數(shù)組元素的值。原來的數(shù)組元素的值被丟棄。

如果不想丟棄原來的元素的值,可以指定第二個(gè)參數(shù)d,則排序的結(jié)果放在數(shù)組d中,原數(shù)組s不變化。

函數(shù)的返回值是原數(shù)組s的元素個(gè)數(shù)。

gensub(r, s, h [, t])

對原始字符串t,將匹配正則表達(dá)式r的子串替換為s。如果字符串h以’g’或’G’開頭,則所有匹配都替換,否則只替換第一個(gè)匹配。函數(shù)的返回值即為執(zhí)行替換后的字符串,也就是說,原始字符串t不會被修改。

如果不指定參數(shù)t,就從當(dāng)前record中讀取,即$0。

在s中,可以通過/1~/9來指代r中第n個(gè)圓括號中的匹配項(xiàng),參考下面的例子1。/0或'&'則表示整個(gè)匹配的內(nèi)容。

gsub(r, s [, t])

對原始字符串t,將匹配正則表達(dá)式r的子串全部替換為s。函數(shù)的返回值為匹配到的子串的個(gè)數(shù),也就是說,原始字符串t會被修改。

如果不指定參數(shù)t,就從當(dāng)前record中讀取,即$0。

在s中,'&'則表示整個(gè)匹配的內(nèi)容。如果要書寫字符’&'的原意,要寫作"//&"。

index(s, t)

返回字符串t在字符串s中第一次出現(xiàn)的位置。例如index(“abcdefg”, “def”)返回4,即index從1開始。如果沒找到子串t,則返回0。

length([s])

返回字符串s的長度,如果沒有參數(shù)s,則返回$0的長度。也可以傳入一個(gè)數(shù)組,這時(shí)返回?cái)?shù)組元素的個(gè)數(shù)。

match(s, r [, a])

在字符串s中匹配正則表達(dá)式r,匹配成功則返回子串的位置(index從1開始),并更新RSTART和RLENGTH,匹配失敗則返回0;

如果有第三個(gè)參數(shù)a,則正則表達(dá)式r中每個(gè)圓括號的匹配內(nèi)容會被依次賦值給數(shù)組a[1]~a[n],而整個(gè)的匹配內(nèi)容則賦值給a[0]。同時(shí),a[m, "start"]和a[m, "length"]兩個(gè)數(shù)組下標(biāo)成員的值為a[m]在s中的位置和字符串長度。

見下面的例子2。

注意,如果在調(diào)用match()之前數(shù)組a不為空,則會先清空a。

split(s, a [, r])

將字符串s按照正則表達(dá)式r作為分隔符來分割,分割成的每個(gè)field保存在數(shù)組a中,函數(shù)返回fields的數(shù)量。

如果沒有r參數(shù),則根據(jù)FS來分割。

注意,如果在調(diào)用split()之前數(shù)組a不為空,則會先清空a。

sprintf(fmt, expr-list)

根據(jù)格式fmt打印表達(dá)式列表expr-list,最終的字符串作為返回值。例如:

sprintf("name%d:%s, name%d:%s", 1, "George", 2, "Tim");

strtonum(str)

將字符串轉(zhuǎn)換為數(shù)值,可識別八進(jìn)制(以0開頭)和十六進(jìn)制(以0x或0X開頭)。例如strtonum(“34”),strtonum(34.50),strtonum(“017”)。

sub(r, s [, t])

同gsub,但只替換第一個(gè)匹配的子串。

substr(s, i [, n])

獲取字符串s中,從第i個(gè)字符開始的n個(gè)字符形成的子串,該子串作為返回值。參數(shù)i從1開始。

tolower(str)

將str中的大寫字母都轉(zhuǎn)換為小寫字母后作為函數(shù)返回值。

toupper(str)

將str中的小寫字母都轉(zhuǎn)換為大寫字母后作為函數(shù)返回值。

注意,gawk3.1.5支持多字節(jié)的字符,這意味著index()/length()/substr()/match()都是針對字符起作用而不是字節(jié)。

例子1,匹配“me again”,然后將其中的me改為her:

[root@ubuntu]awk_test:$ awk 'BEGIN{result=gensub("(me) (again)", "her //2", "g", "tell me again, you go again"); print result}' awk_test.txt tell her again, you go again

前面在sed命令中也講到過這種用法,不過這里圓括號不需要加反斜杠轉(zhuǎn)義,并且"/2"要寫成"//2"。

例子2,測試帶第三個(gè)參數(shù)的match函數(shù):
[root@ubuntu]awk_test:$ awk 'BEGIN{sstr="name1:George, name2:Tim";pos=match(sstr, "name[1-9]:([a-zA-Z]*), name[1-9]:([a-zA-Z]*)", list); /print pos; print RSTART" "RLENGTH; for (i=0; i<=2; i++) print list[i], list[i, "start"], list[i, "length"];}' awk_test.txt11 23name1:George, name2:Tim, 1 23George 7 6Tim 21 3例子3,split函數(shù)測試:
[root@ubuntu]awk_test:$ awk 'BEGIN{sstr="name1:George, name2:Tim, name3:Jason";fcnt=split(sstr, list, "name[[:digit:]]+:"); print fcnt; /for (i=0; i<=fcnt; i++) print list[i];}' awk_test.txt

時(shí)間函數(shù)

由于AWK主要的用處就是處理包含時(shí)間戳信息的大型日志文件。因此AWK提供了以下時(shí)間函數(shù)來獲取和轉(zhuǎn)換時(shí)間戳:

mktime(datespec)  將datespec轉(zhuǎn)換為相對于1970-01-01零點(diǎn)的秒數(shù)。參數(shù)datespec的格式為:“YYYY MM DD HH MMSS[ DST]”,其中夏令時(shí)標(biāo)志DST是可選的。例如mktime("2017 2 6 22 54 00")即為2017年2月6日22時(shí)54分0秒,注意這個(gè)時(shí)間是算上時(shí)區(qū)的。舉例來說,在東8區(qū),mktime("19701 1 8 0 1")的返回值為1。

strftime([format [, timestamp[, utc-flag]]])  將timestamp轉(zhuǎn)換為format指定的格式,timestamp需為相對于1970-01-01零點(diǎn)的秒數(shù)。如果utc-flag不為0或null,則轉(zhuǎn)換結(jié)果是UTC時(shí)間,否則是本地時(shí)間。如果不帶timestamp參數(shù),則使用當(dāng)前時(shí)間;如果不帶timestamp和format參數(shù),則format默認(rèn)與date命令結(jié)果的格式相同,format參數(shù)可用的格式請參考C語言中的strftime()函數(shù),也可參考Effective AWKProgramming[2]中的說明。

systime()  將當(dāng)前時(shí)間轉(zhuǎn)換為相對于1970-01-01零點(diǎn)的秒數(shù)。

位操作函數(shù)

Gawk3.1開始的版本,提供了下面的位運(yùn)算函數(shù):

函數(shù)

作用

and(v1, v2)

按位與

compl(val)

按位取反,同C語言中的'~'運(yùn)算符

lshift(val, count)     

val左移count位,即val << count

or(v1, v2)

按位或

rshift(val, count)

val右移count位(高位補(bǔ)符號位),即val >> count

xor(v1, v2)

按位異或

自定義函數(shù)

AWK中可以自定義函數(shù),形式如下:

function name(parameter list) { statements }

func name(parameter list) { statements }

其中,name是函數(shù)名,前面添加關(guān)鍵字function或func。圓括號內(nèi)是形參列表,后面大括號內(nèi)書寫函數(shù)的實(shí)現(xiàn)。

例如下面的例子:

function add_INT(a, b){    return (a+b);}function add_ARRAY(array){    sum = 0;    for(i in array)    {        sum += array[i];    }    return sum;}BEGIN {aint[0]=10; aint[1]=11; aint[2]=12;print add_ARRAY(aint); print add_INT(12, 78);}

注意,對于自定義函數(shù),在調(diào)用函數(shù)時(shí),函數(shù)名和左圓括號之間不能有空格(AWK的內(nèi)置函數(shù)沒有這個(gè)限制)。

在AWK中,所有的變量都是全局的,那么就可能出現(xiàn)一個(gè)函數(shù)中的局部變量和主程序的變量重名。如果想避免這種情況,可以在函數(shù)的參數(shù)列表里指明局部變量,方法是將局部變量寫在形參后面,并且用多個(gè)空格與形參列表分開。

例如:
function test(a, b,     c){    c = 20;    sum = a + b;}BEGIN {c = 10;sum = 5;test(11, 22);print c" "sum;}

這個(gè)例子中,有c和sum兩個(gè)變量,在函數(shù)test中,會修改c和sum,但是由于指明了c在test()中是作為局部變量的,因此不會影響主程序中c的值。所以print打印出的結(jié)果是“10 33”。

實(shí)際上,參數(shù)列表里的形參都會被認(rèn)為是局部的,用多個(gè)空格分開的做法只是為了代碼的可讀性。

當(dāng)需要將一段通用代碼制作成庫函數(shù)時(shí),自定義函數(shù)就派上了用場,可以配合--source選項(xiàng)來在命令行程序中引用庫函數(shù)。

一些建議:在自定義函數(shù)內(nèi)部,盡量避免定義外部可能使用的變量,例如“i”,“j”這樣的變量,在外部程序中很可能用到,因此在函數(shù)內(nèi)部就不要用這樣的變量命名。建議在函數(shù)內(nèi)變量命名時(shí)以“_”開頭來避免沖突。另外,變量和函數(shù)的命名盡量體現(xiàn)它的作用和含義。最后,如果函數(shù)內(nèi)定義了外部可以使用的全局變量,變量名可以第一個(gè)字母大寫,如“Optind”以和局部變量區(qū)別(不全部大寫是為了防止和AWK內(nèi)置變量混淆)。

可以參考Effective AWK Programming[2]中第10章的部分庫函數(shù)的實(shí)現(xiàn)和第11章的自定義函數(shù)舉例來學(xué)習(xí)自定義函數(shù)的寫法。

信號

pgawk可接收SIGUSR1和SIGHUP兩個(gè)信號。SIGUSR1信號會使pgawk生成profile文件(如之前--profile所述),包含自定義函數(shù)的調(diào)用棧,之后pgawk程序繼續(xù)運(yùn)行。SIGHUP信號同樣會產(chǎn)生profile文件,之后pgawk程序退出。

返回值

Gawk執(zhí)行正確返回EXIT_SUCCESS,通常是0;執(zhí)行失敗返回EXIT_FAILURE,通常是1;如果發(fā)生嚴(yán)重錯(cuò)誤,返回2,但有些系統(tǒng)上會返回EXIT_FAILURE。

如果exit語句指定了返回值,則gawk返回這個(gè)指定的值。

參考資料

[1] Gawk(1) manpage for GNU Awk 3.1.8

[2] Effective AWK Programming: http://www.gnu.org/software/gawk/manual/gawk.html


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 欧美亚洲免费 | 日韩一级视频 | 国产精品久久久久久久久福交 | 成人av网页| 国产一级片在线播放 | av一区在线观看 | 久久4| av2014天堂网 | 性色在线 | 欧美日b | 久久精品成人欧美大片 | 日韩视频在线免费观看 | 在线视频亚洲 | 狠狠视频 | 国产在线视频网 | 国产精品入口久久 | 天天操网| 99在线国产 | 日韩欧美国产一区二区 | aaaa大片| 毛片免费观看视频 | 久久久com | 午夜黄色av | 亚洲婷婷免费 | 久久蜜臀 | 污视频网站在线看 | 亚洲国产一二区 | 日本久久久亚洲精品 | 欧美日一级片 | 性视频网站免费 | 亚洲1级片| 亚洲精品午夜视频 | 羞羞视频在线免费观看 | 国产黄色在线观看 | www.国产在线| 久久一二区 | 成年人在线看 | 国产精品久久久久久久一区探花 | 色婷婷中文 | 国产激情的老师在线播放 | 免费看爱爱视频 |