一. AWK 說(shuō)明
awk是一種編程語(yǔ)言,他可以做數(shù)學(xué)運(yùn)算,流程控制語(yǔ)句,流控制,還有樣式裝入的功能。用于在linux/unix下對(duì)文本和數(shù)據(jù)進(jìn)行處理。數(shù)據(jù)可以來(lái)自標(biāo)準(zhǔn)輸入、一個(gè)或多個(gè)文件,或其它命令的輸出。它支持用戶自定義函數(shù)和動(dòng)態(tài)正則表達(dá)式等先進(jìn)功能,是linux/unix下的一個(gè)強(qiáng)大編程工具。它在命令行中使用,但更多是作為腳本來(lái)使用。
awk的處理文本和數(shù)據(jù)的方式:它逐行掃描文件,從第一行到最后一行,尋找匹配的特定模式的行,并在這些行上進(jìn)行你想要的操作。如果沒(méi)有指定處理動(dòng)作,則把匹配的行顯示到標(biāo)準(zhǔn)輸出(屏幕),如果沒(méi)有指定模式,則所有被操作所指定的行都被處理。
awk分別代表其作者姓氏的第一個(gè)字母。因?yàn)樗淖髡呤侨齻€(gè)人,分別是Alfred Aho、Brian Kernighan、Peter Weinberger。把a(bǔ)wk定義為:樣式掃描處理語(yǔ)言。
awk吸收了C語(yǔ)言很多的特點(diǎn),所以與C語(yǔ)言有點(diǎn)類擬。
gawk是awk的GNU版本,它提供了Bell實(shí)驗(yàn)室和GNU的一些擴(kuò)展。下面介紹的awk是以GUN的gawk為例的,在linux系統(tǒng)中已把a(bǔ)wk鏈接到gawk,所以下面全部以awk進(jìn)行介紹。
使用方法
awk'{pattern + action}' {filenames}
盡管操作可能會(huì)很復(fù)雜,但語(yǔ)法總是這樣,其中 pattern 表示 AWK 在數(shù)據(jù)中查找的內(nèi)容,而 action 是在找到匹配內(nèi)容時(shí)所執(zhí)行的一系列命令?;ɡㄌ?hào)({})不需要在程序中始終出現(xiàn),但它們用于根據(jù)特定的模式對(duì)一系列指令進(jìn)行分組。 pattern就是要表示的正則表達(dá)式,用斜杠括起來(lái)。
awk語(yǔ)言的最基本功能是在文件或者字符串中基于指定規(guī)則瀏覽和抽取信息,awk抽取信息后,才能進(jìn)行其他文本操作。完整的awk腳本通常用來(lái)格式化文本文件中的信息。
通常,awk是以文件的一行為處理單位的。awk每接收文件的一行,然后執(zhí)行相應(yīng)的命令,來(lái)處理文本。
調(diào)用awk
有三種方式調(diào)用awk
1.命令行方式awk [-F field-separator] 'commands' input-file(s)其中,commands 是真正awk命令,[-F域分隔符]是可選的。 input-file(s) 是待處理的文件。在awk中,文件的每一行中,由域分隔符分開的每一項(xiàng)稱為一個(gè)域。通常,在不指名-F域分隔符的情況下,默認(rèn)的域分隔符是空格。
2.shell腳本方式將所有的awk命令插入一個(gè)文件,并使awk程序可執(zhí)行,然后awk命令解釋器作為腳本的首行,一遍通過(guò)鍵入腳本名稱來(lái)調(diào)用。相當(dāng)于shell腳本首行的:#!/bin/sh可以換成:#!/bin/awk
3.將所有的awk命令插入一個(gè)單獨(dú)文件,然后調(diào)用:awk -f awk-script-file input-file(s)其中,-f選項(xiàng)加載awk-script-file中的awk腳本,input-file(s)跟上面的是一樣的。
搜索/etc/passwd有root關(guān)鍵字的所有行
#awk -F: '/root/' /etc/passwdroot:x:0:0:root:/root:/bin/bash
這種是pattern的使用示例,匹配了pattern(這里是root)的行才會(huì)執(zhí)行action(沒(méi)有指定action,默認(rèn)輸出每行的內(nèi)容)。
搜索支持正則,例如找root開頭的: awk -F: '/^root/' /etc/passwd
搜索/etc/passwd有root關(guān)鍵字的所有行,并顯示對(duì)應(yīng)的shell
/bin/bash```
這里指定了action{print $7}
二. awk命令格式和選項(xiàng)
2.1\. awk的語(yǔ)法有兩種形式
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
[root@pacteralinux ~]# last -n 5
root pts/0 182.151.205.254 Tue Dec 17 11:27 still logged in
root pts/1 182.151.205.254 Mon Dec 16 16:05 - 17:38 (01:33)
root pts/0 182.151.205.254 Mon Dec 16 15:44 - 17:41 (01:57)
root pts/3 182.151.205.254 Mon Dec 16 15:18 - 15:43 (00:25)
root pts/2 182.151.205.254 Mon Dec 16 15:17 - 15:29 (00:12)
wtmp begins Tue Dec 18 05:48:21 2012
[root@pacteralinux ~]# last -n 5|awk '{print $1}'
root
root
root
root
root
wtmp
[root@pacteralinux ~]# last -n 5|awk '{print $0}'
root pts/0 182.151.205.254 Tue Dec 17 11:27 still logged in
root pts/1 182.151.205.254 Mon Dec 16 16:05 - 17:38 (01:33)
root pts/0 182.151.205.254 Mon Dec 16 15:44 - 17:41 (01:57)
root pts/3 182.151.205.254 Mon Dec 16 15:18 - 15:43 (00:25)
root pts/2 182.151.205.254 Mon Dec 16 15:17 - 15:29 (00:12)
wtmp begins Tue Dec 18 05:48:21 2012
這種是awk+action的示例,每行都會(huì)執(zhí)行action{print $1}。
2.2. 命令選項(xiàng)
(1)-F fs or --field-separator fs :指定輸入文件折分隔符,fs是一個(gè)字符串或者是一個(gè)正則表達(dá)式,如-F:。
(2)-v var=value or --asign var=value :賦值一個(gè)用戶定義變量。
(3)-f scripfile or --file scriptfile :從腳本文件中讀取awk命令。
(4)-mf nnn and -mr nnn :對(duì)nnn值設(shè)置內(nèi)在限制,-mf選項(xiàng)限制分配給nnn的最大塊數(shù)目;-mr選項(xiàng)限制記錄的最大數(shù)目。這兩個(gè)功能是Bell實(shí)驗(yàn)室版awk的擴(kuò)展功能,在標(biāo)準(zhǔn)awk中不適用。
(5)-W compact or --compat, -W traditional or --traditional :在兼容模式下運(yùn)行awk。所以gawk的行為和標(biāo)準(zhǔn)的awk完全一樣,所有的awk擴(kuò)展都被忽略。
(6)-W copyleft or --copyleft, -W copyright or --copyright :打印簡(jiǎn)短的版權(quán)信息。
(7)-W help or --help, -W usage or --usage :打印全部awk選項(xiàng)和每個(gè)選項(xiàng)的簡(jiǎn)短說(shuō)明。
(8)-W lint or --lint :打印不能向傳統(tǒng)unix平臺(tái)移植的結(jié)構(gòu)的警告。
(9)-W lint-old or --lint-old :打印關(guān)于不能向傳統(tǒng)unix平臺(tái)移植的結(jié)構(gòu)的警告。
(10)-W posix :打開兼容模式。但有以下限制,不識(shí)別:/x、函數(shù)關(guān)鍵字、func、換碼序列以及當(dāng)fs是一個(gè)空格時(shí),將新行作為一個(gè)域分隔符;操作符**和**=不能代替^和^=;fflush無(wú)效。
(11)-W re-interval or --re-inerval :允許間隔正則表達(dá)式的使用,參考(grep中的Posix字符類),如括號(hào)表達(dá)式[[:alpha:]]。
(12)-W source program-text or --source program-text :使用program-text作為源代碼,可與-f命令混用。
(13)-W version or --version :打印bug報(bào)告信息的版本。
三. 模式和操作
awk腳本是由模式和操作組成的:
pattern {action} 如$ awk '/root/' test,或$ awk '$3 < 100' test。
兩者是可選的,如果沒(méi)有模式,則action應(yīng)用到全部記錄,如果沒(méi)有action,則輸出匹配全部記錄。默認(rèn)情況下,每一個(gè)輸入行都是一條記錄,但用戶可通過(guò)RS變量指定不同的分隔符進(jìn)行分隔。
3.1. 模式
模式可以是以下任意一個(gè):
(1)正則表達(dá)式:使用通配符的擴(kuò)展集。
(2)關(guān)系表達(dá)式:可以用下面運(yùn)算符表中的關(guān)系運(yùn)算符進(jìn)行操作,可以是字符(3)串或數(shù)字的比較,如$2>%1選擇第二個(gè)字段比第一個(gè)字段長(zhǎng)的行。
(4)模式匹配表達(dá)式:用運(yùn)算符~(匹配)和~!(不匹配)。
(5)模式,模式:指定一個(gè)行的范圍。該語(yǔ)法不能包括BEGIN和END模式。
(6)BEGIN:讓用戶指定在第一條輸入記錄被處理之前所發(fā)生的動(dòng)作,通常可在這里設(shè)置全局變量。
(7)END:讓用戶在最后一條輸入記錄被讀取之后發(fā)生的動(dòng)作。
如果只是顯示/etc/passwd的賬戶和賬戶對(duì)應(yīng)的shell,而賬戶與shell之間以逗號(hào)分割,而且在所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"。
[root@pacteralinux ~]# cat /etc/passwd|awk -F : 'begin {print "name shell"} {print $1,$7} end {print "blue bash"}'|head -n 5
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
[root@pacteralinux ~]# cat /etc/passwd|awk -F : 'BEGIN {print "name shell"} {print $1,$7} end {print "blue bash"}'|head -n 5
name shell
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
[root@pacteralinux ~]# cat /etc/passwd|awk -F : 'BEGIN {print "name shell"} {print $1,$7} END {print "blue bash"}'
name shell
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
shutdown /sbin/shutdown
halt /sbin/halt
mail /sbin/nologin
uucp /sbin/nologin
operator /sbin/nologin
games /sbin/nologin
gopher /sbin/nologin
ftp /sbin/nologin
nobody /sbin/nologin
dbus /sbin/nologin
vcsa /sbin/nologin
rpc /sbin/nologin
abrt /sbin/nologin
haldaemon /sbin/nologin
ntp /sbin/nologin
saslauth /sbin/nologin
postfix /sbin/nologin
rpcuser /sbin/nologin
nfsnobody /sbin/nologin
sshd /sbin/nologin
tcpdump /sbin/nologin
oprofile /sbin/nologin
mysql /bin/bash
blue bash
注意:begin和and要大寫!??!
其他一些嘗試:
[root@pacteralinux ~]# cat /etc/passwd|awk -F : 'BEGIN {print "name\tshell"} {print "$1\t$7"} END {print "blue\tbash"}'
name shell
$1 $7
$1 $7
$1 $7
$1 $7
。。。。。。
。。。。。。
[root@pacteralinux ~]# cat /etc/passwd|awk -F : 'BEGIN {print "name\tshell"} {print '$1\t$7'} END {print "blue\tbash"}'
name shell
空
空
:
blue bash
3.2. 操作
操作由一人或多個(gè)命令、函數(shù)、表達(dá)式組成,之間由換行符或分號(hào)隔開,并位于大括號(hào)內(nèi)。主要有四部份:
(1)變量或數(shù)組賦值
(2)輸出命令
(3)內(nèi)置函數(shù)
(4)控制流命令
四. awk的環(huán)境變量
四. awk的環(huán)境變量
變量 描述
$n 當(dāng)前記錄的第n個(gè)字段,字段間由FS分隔。
$0 完整的輸入記錄。
ARGC 命令行參數(shù)的數(shù)目。
ARGIND 命令行中當(dāng)前文件的位置(從0開始算)。
ARGV 包含命令行參數(shù)的數(shù)組。
CONVFMT 數(shù)字轉(zhuǎn)換格式(默認(rèn)值為%.6g)
ENVIRON 環(huán)境變量關(guān)聯(lián)數(shù)組。
ERRNO 最后一個(gè)系統(tǒng)錯(cuò)誤的描述。
FIELDWIDTHS 字段寬度列表(用空格鍵分隔)。
FILENAME 當(dāng)前文件名。awk瀏覽的文件名
FNR 同NR,但相對(duì)于當(dāng)前文件。
FS 字段分隔符(默認(rèn)是任何空格)。
IGNORECASE 如果為真,則進(jìn)行忽略大小寫的匹配。
NF 當(dāng)前記錄中的字段數(shù)。當(dāng)前記錄域的個(gè)數(shù)
NR 當(dāng)前記錄數(shù)。
OFMT 數(shù)字的輸出格式(默認(rèn)值是%.6g)。
OFS 輸出字段分隔符(默認(rèn)值是一個(gè)空格)。
ORS 輸出記錄分隔符(默認(rèn)值是一個(gè)換行符)。
RLENGTH 由match函數(shù)所匹配的字符串的長(zhǎng)度。
RS 記錄分隔符(默認(rèn)是一個(gè)換行符)。
RSTART 由match函數(shù)所匹配的字符串的第一個(gè)位置。
SUBSEP 數(shù)組下標(biāo)分隔符(默認(rèn)值是/034)。
此外,$0變量是指整條記錄。$1表示當(dāng)前行的第一個(gè)域,$2表示當(dāng)前行的第二個(gè)域,......以此類推。
統(tǒng)計(jì)/etc/passwd:文件名,每行的行號(hào),每行的列數(shù),對(duì)應(yīng)的完整行內(nèi)容:
[root@pacteralinux ~]# awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin
filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin
filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin
filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
filename:/etc/passwd,linenumber:6,columns:7,linecontent:sync:x:5:0:sync:/sbin:/bin/sync
filename:/etc/passwd,linenumber:7,columns:7,linecontent:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
filename:/etc/passwd,linenumber:8,columns:7,linecontent:halt:x:7:0:halt:/sbin:/sbin/halt
使用printf替代print,可以讓代碼更加簡(jiǎn)潔,易讀
[root@pacteralinux ~]# awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin
filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin
filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin
filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
print和printf
awk中同時(shí)提供了print和printf兩種打印輸出的函數(shù)。
其中print函數(shù)的參數(shù)可以是變量、數(shù)值或者字符串。字符串必須用雙引號(hào)引用,參數(shù)用逗號(hào)分隔。如果沒(méi)有逗號(hào),參數(shù)就串聯(lián)在一起而無(wú)法區(qū)分。這里,逗號(hào)的作用與輸出文件的分隔符的作用是一樣的,只是后者是空格而已。
printf函數(shù),其用法和c語(yǔ)言中printf基本相似,可以格式化字符串,輸出復(fù)雜時(shí),printf更加好用,代碼更易懂。
下面統(tǒng)計(jì)/etc/passwd的賬戶人數(shù)
[root@pacteralinux ~]# awk '{count++;} END{print "user count is ", count}' /etc/passwd
user count is 29
[root@pacteralinux ~]#
這里沒(méi)有初始化count,雖然默認(rèn)是0,但是妥當(dāng)?shù)淖龇ㄟ€是初始化為0:
```[root@pacteralinux ~]# awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd
[start]user count is 0
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/cache/rpcbind:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
saslauth:x:499:76:"Saslauthd user":/var/empty/saslauth:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
oprofile:x:16:16:Special user account to be used by OProfile:/home/oprofile:/sbin/nologin
mysql:x:498:501::/home/mysql:/bin/bash
[end]user count is 29
統(tǒng)計(jì)某個(gè)文件夾下的文件占用的字節(jié)數(shù)
ls -l |awk'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
[end]size is 8657198
如果以M為單位顯示:
ls -l |awk'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}'
[end]size is 8.25889 M
注意,統(tǒng)計(jì)不包括文件夾的子目錄。
五. awk運(yùn)算符
運(yùn)算符 描述
= += -= *= /= %= ^= **= 賦值
?: C條件表達(dá)式
|| 邏輯或
&& 邏輯與
~ ~! 匹配正則表達(dá)式和不匹配正則表達(dá)式
< <= > >= != == 關(guān)系運(yùn)算符
空格 連接
- 加,減
- / & 乘,除與求余
- ! 一元加,減和邏輯非
^ *** 求冪
++ -- 增加或減少,作為前綴或后綴
$ 字段引用
in 數(shù)組成員
- ! 一元加,減和邏輯非
六. 記錄和域
6.1. 記錄
awk把每一個(gè)以換行符結(jié)束的行稱為一個(gè)記錄。
記錄分隔符:默認(rèn)的輸入和輸出的分隔符都是回車,保存在內(nèi)建變量ORS和RS中。
$0變量:它指的是整條記錄。如$ awk '{print $0}' test將輸出test文件中的所有記錄。
變量NR:一個(gè)計(jì)數(shù)器,每處理完一條記錄,NR的值就增加1。
如$ awk '{print NR,$0}' test將輸出test文件中所有記錄,并在記錄前顯示記錄號(hào)。
6.2. 域
記錄中每個(gè)單詞稱做“域”,默認(rèn)情況下以空格或tab分隔。awk可跟蹤域的個(gè)數(shù),并在內(nèi)建變量NF中保存該值。如$ awk '{print $1,$3}' test將打印test文件中第一和第三個(gè)以空格分開的列(域)。
6.3. 域分隔符
內(nèi)建變量FS保存輸入域分隔符的值,默認(rèn)是空格或tab。我們可以通過(guò)-F命令行選項(xiàng)修改FS的值。如$ awk -F: '{print $1,$5}' test將打印以冒號(hào)為分隔符的第一,第五列的內(nèi)容。
可以同時(shí)使用多個(gè)域分隔符,這時(shí)應(yīng)該把分隔符寫成放到方括號(hào)中,如$awk -F'[:/t]' '{print $1,$3}' test,表示以空格、冒號(hào)和tab作為分隔符。
輸出域的分隔符默認(rèn)是一個(gè)空格,保存在OFS中。如$ awk -F: '{print $1,$5}' test,$1和$5間的逗號(hào)就是OFS的值。
[root@pacteralinux ~]# cat /etc/passwd|awk -F : '{print $1,$3}'|head -n 5
root 0
bin 1
daemon 2
adm 3
lp 4
[root@pacteralinux ~]#
[root@pacteralinux ~]# cat /etc/passwd|awk -F : '{print $1"\t"$3}'|head -n 5
root 0
bin 1
daemon 2
adm 3
lp 4
[root@pacteralinux ~]# cat /etc/passwd|awk -F : '{print $1":"$3}'|head -n 5
root:0
bin:1
daemon:2
adm:3
lp:4
[root@pacteralinux ~]# cat /etc/passwd|awk -F : '{print $1"qq"$3}'|head -n 5
rootqq0
binqq1
daemonqq2
admqq3
lpqq4
[root@pacteralinux ~]# cat /etc/passwd|awk -F : '{print $1","$3}'|head -n 5
root,0
bin,1
daemon,2
adm,3
lp,4
七. gawk專用正則表達(dá)式元字符
以下幾個(gè)是gawk專用的,不適合unix版本的awk。
(1)/Y :匹配一個(gè)單詞開頭或者末尾的空字符串。
(2)/B:匹配單詞內(nèi)的空字符串。
(3)/<:匹配一個(gè)單詞的開頭的空字符串,錨定開始。
(4)/> :匹配一個(gè)單詞的末尾的空字符串,錨定末尾。
(5)/w :匹配一個(gè)字母數(shù)字組成的單詞。
(6)/W :匹配一個(gè)非字母數(shù)字組成的單詞。
(7)/‘:匹配字符串開頭的一個(gè)空字符串。
(8)/' :匹配字符串末尾的一個(gè)空字符串。
八. 匹配操作符(~)
用來(lái)在記錄或者域內(nèi)匹配正則表達(dá)式。如$ awk '$1 ~/^root/' test將顯示test文件第一列中以root開頭的行。
九. 比較表達(dá)式
conditional expression1 ? expression2: expression3,
例如:$ awk '{max = {$1 > $3} ? $1: $3: print max}' test。如果第一個(gè)域大于第三個(gè)域,$1就賦值給max,否則$3就賦值給max。
$ awk '$1 + $2 < 100' test。如果第一和第二個(gè)域相加大于100,則打印這些行。
$ awk '$1 > 5 && $2 < 10' test,如果第一個(gè)域大于5,并且第二個(gè)域小于10,則打印這些行。
十. 范圍模板
范圍模板匹配從第一個(gè)模板的第一次出現(xiàn)到第二個(gè)模板的第一次出現(xiàn)之間所有行。如果有一個(gè)模板沒(méi)出現(xiàn),則匹配到開頭或末尾。如$ awk '/root/,/mysql/' test將顯示root第一次出現(xiàn)到mysql第一次出現(xiàn)之間的所有行。
十一. 條件語(yǔ)句
awk中的條件語(yǔ)句是從C語(yǔ)言中借鑒來(lái)的,見如下聲明方式:
if (expression) {
statement;
statement;
... ...}
if (expression) {
statement;}
else {
statement2;}
if (expression) {
statement1;}
elseif (expression1) {
statement2;} else {
statement3;}
統(tǒng)計(jì)某個(gè)文件夾下的文件占用的字節(jié)數(shù),過(guò)濾4096大小的文件(一般都是文件夾):
[root@pacteralinux ~]# ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'
[start]size is 0
[end]size is 153.079 M
[root@pacteralinux ~]#
循環(huán)語(yǔ)句
awk中的循環(huán)語(yǔ)句同樣借鑒于C語(yǔ)言,支持while、do/while、for、break、continue,這些關(guān)鍵字的語(yǔ)義和C語(yǔ)言中的語(yǔ)義完全相同。
數(shù)組
因?yàn)閍wk中數(shù)組的下標(biāo)可以是數(shù)字和字母,數(shù)組的下標(biāo)通常被稱為關(guān)鍵字(key)。值和關(guān)鍵字都存儲(chǔ)在內(nèi)部的一張針對(duì)key/value應(yīng)用hash的表格里。由于hash不是順序存儲(chǔ),因此在顯示數(shù)組內(nèi)容時(shí)會(huì)發(fā)現(xiàn),它們并不是按照你預(yù)料的順序顯示出來(lái)的。數(shù)組和變量一樣,都是在使用時(shí)自動(dòng)創(chuàng)建的,awk也同樣會(huì)自動(dòng)判斷其存儲(chǔ)的是數(shù)字還是字符串。一般而言,awk中的數(shù)組用來(lái)從記錄中收集信息,可以用于計(jì)算總和、統(tǒng)計(jì)單詞以及跟蹤模板被匹配的次數(shù)等等。
顯示/etc/passwd的賬戶
[root@pacteralinux ~]# awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
0 root
1 bin
2 daemon
3 adm
4 lp
5 sync
6 shutdown
7 halt
8 mail
9 uucp
10 operator
11 games
12 gopher
13 ftp
14 nobody
15 dbus
16 vcsa
17 rpc
18 abrt
19 haldaemon
20 ntp
21 saslauth
22 postfix
23 rpcuser
24 nfsnobody
25 sshd
26 tcpdump
27 oprofile
28 mysql
這里使用for循環(huán)遍歷數(shù)組
awk編程的內(nèi)容極多,這里只羅列簡(jiǎn)單常用的用法,更多請(qǐng)參考 http://www.gnu.org/software/gawk/manual/gawk.html
十一. 示例
1、awk '/101/' file 顯示文件file中包含101的匹配行。
awk '/101/,/105/' file
awk '$1 == 5' file
awk '$1 == "CT"' file 注意必須帶雙引號(hào) awk '$1 * $2 >100 ' file
awk '$2 >5 && $2<=15' file
2、awk '{print NR,NF,$1,$NF,}' file 顯示文件file的當(dāng)前記錄號(hào)、域數(shù)和每一行的第一個(gè)和最后一個(gè)域。
awk '/101/ {print $1,$2 + 10}' file 顯示文件file的匹配行的第一、二個(gè)域加10。 awk '/101/ {print $1$2}' file
awk '/101/ {print $1 $2}' file 顯示文件file的匹配行的第一、二個(gè)域,但顯示時(shí)域中間沒(méi)有分隔符。
3、df | awk '$4>1000000 ' 通過(guò)管道符獲得輸入,如:顯示第4個(gè)域滿足條件的行。
4、awk -F "|" '{print $1}' file 按照新的分隔符“|”進(jìn)行操作。 awk 'BEGIN { FS="[: /t|]" }
{print $1,$2,$3}' file 通過(guò)設(shè)置輸入分隔符(FS="[: /t|]")修改輸入分隔符。 Sep="|"
awk -F $Sep '{print $1}' file 按照環(huán)境變量Sep的值做為分隔符。 awk -F '[ :/t|]' '{print $1}' file 按照正則表達(dá)式的值做為分隔符,這里代表空格、:、TAB、|同時(shí)做為分隔符。 awk -F '[][]' '{print $1}' file 按照正則表達(dá)式的值做為分隔符,這里代表[、]
5、awk -f awkfile file 通過(guò)文件awkfile的內(nèi)容依次進(jìn)行控制。
cat awkfile
/101/{print "/047 Hello! /047"} --遇到匹配行以后打印 ' Hello! './047代表單引號(hào)。 {print $1,$2} --因?yàn)闆](méi)有模式控制,打印每一行的前兩個(gè)域。
6、awk '$1 ~ /101/ {print $1}' file 顯示文件中第一個(gè)域匹配101的行(記錄)。
7、awk 'BEGIN { OFS="%"}
{print $1,$2}' file 通過(guò)設(shè)置輸出分隔符(OFS="%")修改輸出格式。
8、awk 'BEGIN { max=100 ;print "max=" max}
BEGIN表示在處理任意行之前進(jìn)行的操作。 {max=($1 >max ?$1:max); print $1,"Now max is "max}' file 取得文件第一個(gè)域的最大值。
9、awk '$1 * $2 >100 {print $1}' file顯示文件中第一個(gè)域匹配101的行(記錄)。
10、awk '{$1 == 'Chi' {$3 = 'China'; print}' file 找到匹配行后先將第3個(gè)域替換后再顯示該行(記錄)。 awk '{$7 %= 3; print $7}' file 將第7域被3除,并將余數(shù)賦給第7域再打印。
11、awk '/tom/ {wage=$2+$3; printf wage}' file 找到匹配行后為變量wage賦值并打印該變量。
12、awk '/tom/ {count++;}
END {print "tom was found "count" times"}' file
END表示在所有輸入行處理完后進(jìn)行處理。
13、awk 'gsub(//$/,"");gsub(/,/,""); cost+=$4; END {print "The total is $" cost>"filename"}' file
gsub函數(shù)用空串替換$和,再將結(jié)果輸出到filename中。 1 2 3 $1,200.00
1 2 3 $2,300.00
1 2 3 $4,000.00
awk '{gsub(//$/,"");gsub(/,/,"");
if ($4>1000&&$4<2000) c1+=$4;
else if ($4>2000&&$4<3000) c2+=$4;
else if ($4>3000&&$4<4000) c3+=$4;
else c4+=$4; }
END {printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]/n",c1,c2,c3,c4}"' file
通過(guò)if和else if完成條件語(yǔ)句
awk '{gsub(//$/,"");gsub(/,/,"");
if ($4>3000&&$4<4000) exit;
else c4+=$4; }
END {printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]/n",c1,c2,c3,c4}"' file
通過(guò)exit在某條件時(shí)退出,但是仍執(zhí)行END操作。
awk '{gsub(//$/,"");gsub(/,/,"");
if ($4>3000) next;
else c4+=$4; }
END {printf "c4=[%d]/n",c4}"' file
通過(guò)next在某條件時(shí)跳過(guò)該行,對(duì)下一行執(zhí)行操作。
14、awk '{ print FILENAME,$0 }' file1 file2 file3>fileall
把file1、file2、file3的文件內(nèi)容全部寫到fileall中,格式為打印文件并前置文件名。
15、awk ' $1!=previous { close(previous); previous=$1 } {print substr($0,index($0," ") +1)>$1}' fileall
把合并后的文件重新分拆為3個(gè)文件。并與原文件一致。
16、awk 'BEGIN {"date"|getline d; print d}'
通過(guò)管道把date的執(zhí)行結(jié)果送給getline,并賦給變量d,然后打印。
17、awk 'BEGIN {system("echo "Input your name://c""); getline d;print "/nYour name is",d,"/b!/n"}' 通過(guò)getline命令交互輸入name,并顯示出來(lái)。
awk 'BEGIN {FS=":"; while(getline< "/etc/passwd" >0) { if($1~"050[0-9]") print $1}}'
打印/etc/passwd文件中用戶名包含050x的用戶名。 18、awk '{ i=1;while(i<NF) {print NF,$i;i++}}' file 通過(guò)while語(yǔ)句實(shí)現(xiàn)循環(huán)。 awk '{ for(i=1;i<NF;i++) {print NF,$i}}' file 通過(guò)for語(yǔ)句實(shí)現(xiàn)循環(huán)。
type file|awk -F "/" '
{ for(i=1;i<NF;i++)
{ if(i==NF-1) { printf "%s",$i }
else { printf "%s/",$i } }}'
顯示一個(gè)文件的全路徑。
用for和if顯示日期
awk 'BEGIN {
for(j=1;j<=12;j++)
{ flag=0;
printf "/n%d月份/n",j;
for(i=1;i<=31;i++)
{
if (j==2&&i>28) flag=1;
if ((j==4||j==6||j==9||j==11)&&i>30) flag=1;
if (flag==0) {printf "%02d%02d ",j,i}
}
}
}'
19、在awk中調(diào)用系統(tǒng)變量必須用單引號(hào),如果是雙引號(hào),則表示字符串 Flag=abcd
awk '{print '$Flag'}' 結(jié)果為abcd
awk '{print "$Flag"}' 結(jié)果為$Flag
- 其他小示例
$ awk '/^(no|so)/' test-----打印所有以模式no或so開頭的行。
$ awk '/^[ns]/{print $1}' test-----如果記錄以n或s開頭,就打印這個(gè)記錄。
$ awk '$1 ~/[0-9][0-9]$/(print $1}' test-----如果第一個(gè)域以兩個(gè)數(shù)字結(jié)束就打印這個(gè)記錄。
$ awk '$1 == 100 || $2 < 50' test-----如果第一個(gè)或等于100或者第二個(gè)域小于50,則打印該行。
$ awk '$1 != 10' test-----如果第一個(gè)域不等于10就打印該行。
$ awk '/test/{print $1 + 10}' test-----如果記錄包含正則表達(dá)式test,則第一個(gè)域加10并打印出來(lái)。
$ awk '{print ($1 > 5 ? "ok "$1: "error"$1)}' test-----如果第一個(gè)域大于5則打印問(wèn)號(hào)后面的表達(dá)式值,否則打印冒號(hào)后面的表達(dá)式值。
$ awk '/root/,/mysql/' test----打印以正則表達(dá)式root開頭的記錄到以正則表達(dá)式mysql開頭的記錄范圍內(nèi)的所有記錄。如果找到一個(gè)新的正則表達(dá)式root開頭的記錄,則繼續(xù)打印直到下一個(gè)以正則表達(dá)式mysql開頭的記錄為止,或到文件末尾。