awk 是一種程序語言. 它具備通常程序語言常見的功能.
因awk語言具備某些特色, 如 : 使用直譯器(Interpreter)不需先行編譯; 變量無類型之分(Typeless), 可以使用文字當數組的下標(Associative Array)...等特點. 所以, 使用awk撰寫程序比起使用其它語言更簡潔便利且節省時間. awk還具備一些內建功能, 使得awk擅於處理具數據行(Record), 字段(Field)型態的資料; 此外, awk內建有pipe的功能, 可將處理中的數據傳送給外部的 Shell命令加以處理, 再將Shell命令處理後的數據傳回awk程序, 這個特色也使得awk程序很容易使用系統資源。html
awk讀取輸入文件時,每次讀取一條記錄(record)(默認狀況下按行讀取,因此此時記錄就是行)。每讀取一條記錄,將其保存到$0中,而後執行一次main代碼段
在讀取數據時,可設置表示輸入記錄分隔符的預約義變量RS(Record Separator)來改變每次讀取的記錄模式linux
awk 'BEGIN{RS="\n"}'默認狀況下使用\n換行符進行分隔讀取。 RS="":按段落讀取 RS="\0":一次性讀取全部數據,但有些特殊文件中包含了空字符\0 RS="^$":真正的一次性讀取全部數據,由於非空文件不可能匹配成功 RS="\n+":按行讀取,但忽略全部空行
因此在讀取數據前,能夠改變RS來改變每次讀取數據的模式正則表達式
ID name gender age email phone 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523
3 wmzi female 61 ccc@sohu.com 18848796505
4 wangw female 31 acc@sohu.com 18848796506
5 liub male 56 gdd@163.com 18848796507
6 zhangf female 34 adb@139.com 18848796573
7 guany male 56 eab@189.com 17048796508
8 zhaoy female 35 189@163.com 17058796503
9 huangz male 65 dd@189.com 13648796593
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803
awk [ -- ] program-text file ... (1) awk -f program-file [ -- ] file ... (2) awk -e program-text [ -- ] file ... (3) program-txt是awk命令行中的awk代碼,通常使用單引號包圍 -f program-file表示將awk代碼寫在文件中,而後使用-f選項去執行該文件 -e program-text也用於指定awk代碼,若是要結合文件和命令行一塊兒使用,必須使用-e和-f,不能使用(1)
-e program-text --source program-text 指定awk程序表達式,可結合-f選項同時使用 在使用了-f選項後,若是不使用-e,awk program是不會執行的,它會被看成ARGV的一個參數 -f program-file --file program-file 從文件中讀取awk源代碼來執行,可指定多個-f選項 -F fs --field-separator fs 指定輸入字段分隔符(FS預約義變量也可設置) -n --non-decimal-data 識別文件輸入中的8進制數(0開頭)和16進制數(0x開頭) echo '030' | awk -n '{print $1+0}'
-o [filename] 格式化awk代碼。 不指定filename時,則默認保存到awkprof.out 指定爲`-`時,表示輸出到標準輸出 -v var=val --assign var=val 在BEGIN以前,聲明並賦值變量var,變量可在BEGIN中使用
awk程序中主要語法是 Pattern { Actions}
Pattern:爲匹配模式,即斷定某一行是否符合該模式,而後才執行Actions
Actions:爲執行邏輯,其中多個action若是寫在同一行,則需使用分號分隔shell
pattern和action均可以省略express
省略代碼塊{action},等價於{print}即輸出全部行vim
pattern{action}任何一部分均可以省略數組
pattern中使用邏輯與、非、或數據結構
pattern && pattern # 邏輯與 3>2 && 3>1 {action} pattern || pattern # 邏輯或 3>2 || 3<1 {action} ! pattern # 邏輯取反 !/a.*ef/{action}
經常使用的Patternless
# 1.根據行號篩選 NR==2 # 篩選出第二行 NR>=2 # 輸出第2行和以後的行 # 2.根據正則表達式篩選整行 /qq.com/ # 輸出帶有qq.com的行 $0 ~ /qq.com/ # 等價於上面命令 /^[^@]+$/ # 輸出不包含@符號的行 !/@/ # 輸出不包含@符號的行 # 3.根據字段來篩選行 ($4+0) > 24{print $0} # 輸出第4字段大於24的行 $5 ~ /qq.com/ # 輸出第5字段包含qq.com的行 # 4.將多個篩選條件結合起來進行篩選 NR>=2 && NR<=7 #輸出行數大於等於2而且小於等於7 $3=="male" && $6 ~ /^170/ #輸出第三個字段等於male而且第六個字段不用170開頭 $3=="male" || $6 ~ /^170/ #輸出第三個字段等於male或者第六個字段不用170開頭 # 5.按照範圍進行篩選 flip flop # pattern1,pattern2{action} NR==2,NR==7 # 輸出第2到第7行 NR==2,$6 ~ /^170/ # 輸出第2行到匹配第六個字段170開頭的行
action有不少,例如:dom
awk的 I/O指令 : print, printf( ), getline... awk的 流程控制指令 : if(...){..} else{..}, while(...){...}...
實例:
[root@lgh test]# awk '' test.txt #action和pattern都省了 [root@lgh test]# awk '/163/{print $0}' test.txt #匹配行中有163的行,並輸出 1 zhangs female 34 aaa@163.com 13423394013
5 liub male 56 gdd@163.com 18848796507
8 zhaoy female 35 189@163.com 17058796503 [root@lgh test]# awk '/163/' test.txt #省略action,默認輸出$0 1 zhangs female 34 aaa@163.com 13423394013
5 liub male 56 gdd@163.com 18848796507
8 zhaoy female 35 189@163.com 17058796503 [root@lgh test]# awk '{print $0}' test.txt #省略pattern,輸出所有行 ID name gender age email phone 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523
3 wmzi female 61 ccc@sohu.com 18848796505
4 wangw female 31 acc@sohu.com 18848796506
5 liub male 56 gdd@163.com 18848796507
6 zhangf female 34 adb@139.com 18848796573
7 guany male 56 eab@189.com 17048796508
8 zhaoy female 35 189@163.com 17058796503
9 huangz male 65 dd@189.com 13648796593
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803
預約義變量分爲兩類:控制awk工做的變量和攜帶信息的變量
第一類:控制AWK工做的預約義變量
$0,$1,$2,...$NF:其中$0表示整行數據,$1,$2,...,$NF分別表示該行的第一個字段、第二個字段,...,最後一個字段
RS:輸入記錄分隔符,默認爲換行符\n IGNORECASE:默認值爲0,表示全部的正則匹配不忽略大小寫。設置爲非0值(例如1),以後的匹配將忽略大小寫。例如在BEGIN塊中將其設置爲1,將使FS、RS都以忽略大小寫的方式分隔字段或分隔record FS:讀取記錄後,劃分爲字段的字段分隔符。 FIELDWIDTHS:以指定寬度切割字段而非按照FS。 FPAT:以正則匹配匹配到的結果做爲字段,而非按照FS劃分。 OFS:print命令輸出各字段列表時的輸出字段分隔符,默認爲空格" " ORS:print命令輸出數據時在尾部自動添加的記錄分隔符,默認爲換行符\n CONVFMT:在awk中數值隱式轉換爲字符串時,將根據CONVFMT的格式按照sprintf()的方式自動轉換爲字符串。默認值爲」%.6g OFMT:在print中,數值會根據OFMT的格式按照sprintf()的方式自動轉換爲字符串。默認值爲」%.6g
第二類:攜帶信息的預約義變量
ARGC和ARGV:awk命令行參數的數量、命令參數的數組。 ARGIND:awk當前正在處理的文件在ARGV中的索引位置。因此,若是awk正在處理命令行參數中的某文件,則ARGV[ARGIND] == FILENAME爲真 FILENAME:awk當前正在處理的文件(命令行中指定的文件),因此在BEGIN中該變量值爲空 ENVIRON:保存了Shell的環境變量的數組。例如ENVIRON["HOME"]將返回當前用戶的家目錄 NR:當前已讀總記錄數,多個文件從不會重置爲0,因此它是一直疊加的,能夠直接修改NR,下次讀取記錄時將在此修改值上自增 FNR:當前正在讀取文件的第幾條記錄,每次打開新文件會重置爲0,能夠直接修改FNR,下次讀取記錄時將在此修改值上自增 NF:當前記錄的字段數, RT:在讀取記錄時真正的記錄分隔符, RLENGTH:match()函數正則匹配成功時,所匹配到的字符串長度,若是匹配失敗,該變量值爲-1 RSTART:match()函數匹配成功時,其首字符的索引位置,若是匹配失敗,該變量值爲0 SUBSEP:arr[x,y]中下標分隔符構建成索引時對應的字符,默認值爲\034,是一個不太可能出如今字符串中的不可打印字符。
一、$0,$1,$2,...,$NF
[root@lgh test]# awk '{print $0,$1,$2,$NF}' test.txt #輸出整行,而後輸出第一,第二,和最後一個字段的值 ID name gender age email phone ID name phone 1 zhangs female 34 aaa@163.com 13423394013 1 zhangs 13423394013
2 lisi male 45 abb@gmail.com 15608492523 2 lisi 15608492523
3 wmzi female 61 ccc@sohu.com 18848796505 3 wmzi 18848796505
4 wangw female 31 acc@sohu.com 18848796506 4 wangw 18848796506
5 liub male 56 gdd@163.com 18848796507 5 liub 18848796507
6 zhangf female 34 adb@139.com 18848796573 6 zhangf 18848796573
7 guany male 56 eab@189.com 17048796508 7 guany 17048796508
8 zhaoy female 35 189@163.com 17058796503 8 zhaoy 17058796503
9 huangz male 65 dd@189.com 13648796593 9 huangz 13648796593
10 lvbu male 43 byy@sohu.com 18148796803 10 lvbu 18148796803
11 sunwk male 99 suk@sohu.com 18148706803 11 sunwk 18148706803
二、RS、IGNORECASE
RS有兩種狀況:
RS爲單個字符:直接使用該字符做爲分隔符進行分割記錄
RS爲多個字符:將其當作正則表達式,只要匹配正則表達式的符號,都用來作分割記錄,設置預約義變量INGORECASE爲非零值,表示正則忽略大小寫
[root@lgh test]# echo "bababaABAB" | awk 'BEGIN{IGNORECASE=1;RS="a+"}{print $0}' #正則忽略大小寫切分讀取 b b b B B [root@lgh test]# echo "bababaABAB" | awk 'BEGIN{IGNORECASE=0;RS="a+"}{print $0}' #正則不忽略大小寫切分讀取 b b b ABAB [root@lgh test]# echo "bababaABAB" | awk 'BEGIN{IGNORECASE=1;RS="a"}{print $0}' #非正則,IGNORECASE無效 b b b ABAB
三、分隔符FS、FIELDWIDTHS
[root@lgh test]# awk -F" +|@" '{print $1,$2,$3,$4,$5,$6,$7}' test.txt #正則,一個空格或者多個空格,或者@符進行分割 ID name gender age email phone 1 zhangs female 34 aaa 163.com 13423394013
2 lisi male 45 abb gmail.com 15608492523
3 wmzi female 61 ccc sohu.com 18848796505
4 wangw female 31 acc sohu.com 18848796506
5 liub male 56 gdd 163.com 18848796507
6 zhangf female 34 adb 139.com 18848796573
7 guany male 56 eab 189.com 17048796508
8 zhaoy female 35 189 163.com 17058796503
9 huangz male 65 dd 189.com 13648796593
10 lvbu male 43 byy sohu.com 18148796803
11 sunwk male 99 suk sohu.com 18148706803 [root@lgh test]# awk '{print $1,$2}' FS=":" /etc/passwd | head -2 #使用FS指定:爲分割分 root x bin x [root@lgh test]# awk -F":" '{print $1,$2}' /etc/passwd | head -2 #使用-F指定:分隔符 root x bin x
預約義變量FIELDWIDTHS按字符寬度分割字段
FIELDWIDTHS="1 2 3 4" :表示第一個字段1個字符,第二個2個字符,第三個3個字符,第四個4個字符
[root@lgh test]# cat name.txt #文件內容 ID name gender age email phone 1 female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523 [root@lgh test]# awk '{print $2}' name.txt #獲取第二列,其中female是第三列的內容 name female lisi [root@lgh test]# awk 'BEGIN{FIELDWIDTHS="8 8"}{print $2}' name.txt #正確的獲取第二列 name lisi [root@lgh test]# echo 'bababaABAB' | awk 'BEGIN{FIELDWIDTHS="1 2 3 4"}{print $1,$2,$3,$4}' #使用指定字符長度分割 b ab aba ABAB
四、FS、OFS
FS是讀取行時的字段分割,OFS是輸出時的字段分隔符
[root@lgh test]# awk 'BEGIN{OFS="="}{print $1,$2}' test.txt ID=name 1=zhangs 2=lisi 3=wmzi 4=wangw 5=liub 6=zhangf 7=guany 8=zhaoy 9=huangz 10=lvbu 11=sunwk
[root@lgh test]# awk 'BEGIN{OFS="-"}{$1=$1;print $0}' test.txt #重組$0,修改$1,$2,...,$NF中的內容,以及增大或者減小NF的值,都會產生$0的重組 ID-name-gender-age-email-phone 1-zhangs-female-34-aaa@163.com-13423394013
2-lisi-male-45-abb@gmail.com-15608492523
3-wmzi-female-61-ccc@sohu.com-18848796505
4-wangw-female-31-acc@sohu.com-18848796506
5-liub-male-56-gdd@163.com-18848796507
6-zhangf-female-34-adb@139.com-18848796573
7-guany-male-56-eab@189.com-17048796508
8-zhaoy-female-35-189@163.com-17058796503
9-huangz-male-65-dd@189.com-13648796593
10-lvbu-male-43-byy@sohu.com-18148796803
11-sunwk-male-99-suk@sohu.com-18148706803
五、RS、ORS
RS是讀取時的行分割,ORS是輸出時的行分割
[root@lgh test]# echo -e "a\nb" |awk '{print $1}' #RS默認\n a b [root@lgh test]# echo -e "a\nb" |awk 'BEGIN{ORS="hello word"}{print $1}' #使用hello word代替\n進行輸出 ahello wordbhello word
六、OFMT
變量OFMT(Output format)定義的格式按照sprintf()相同的方式進行格式化。OFMT默認值爲%.6g,表示有效位(整數部分加小數部分)最多爲6。
[root@lgh test]# awk 'BEGIN{OFMT="%.3f";print 3.141592678}' #會進行四捨五入
3.142 [root@lgh test]# awk 'BEGIN{print 3.141592678}'
3.14159
經常使用格式符: %c :將ASCII碼轉換爲字符, %d :轉爲整數 %e :科學計數方法輸出 %o :轉爲8進制輸出 %s :轉爲字符串 %x :轉16進制
七、NR、FNR
NR是該程序讀取的記錄數,FNR是程序讀取某個文件的的記錄數
[root@lgh test]# awk '{print NR,FNR,$0}' test.txt test.txt #NR一直遞增,FNR根據文件從新設置1,而後遞增 1 1 ID name gender age email phone 2 2 1 zhangs female 34 aaa@163.com 13423394013
3 3 2 lisi male 45 abb@gmail.com 15608492523
4 4 3 wmzi female 61 ccc@sohu.com 18848796505
5 5 4 wangw female 31 acc@sohu.com 18848796506
6 6 5 liub male 56 gdd@163.com 18848796507
7 7 6 zhangf female 34 adb@139.com 18848796573
8 8 7 guany male 56 eab@189.com 17048796508
9 9 8 zhaoy female 35 189@163.com 17058796503
10 10 9 huangz male 65 dd@189.com 13648796593
11 11 10 lvbu male 43 byy@sohu.com 18148796803
12 12 11 sunwk male 99 suk@sohu.com 18148706803
13 1 ID name gender age email phone 14 2 1 zhangs female 34 aaa@163.com 13423394013
15 3 2 lisi male 45 abb@gmail.com 15608492523
16 4 3 wmzi female 61 ccc@sohu.com 18848796505
17 5 4 wangw female 31 acc@sohu.com 18848796506
18 6 5 liub male 56 gdd@163.com 18848796507
19 7 6 zhangf female 34 adb@139.com 18848796573
20 8 7 guany male 56 eab@189.com 17048796508
21 9 8 zhaoy female 35 189@163.com 17058796503
22 10 9 huangz male 65 dd@189.com 13648796593
23 11 10 lvbu male 43 byy@sohu.com 18148796803
24 12 11 sunwk male 99 suk@sohu.com 18148706803
八、ARGS、ARGV
預約義變量ARGV是一個數組,包含了全部的命令行參數。該數組使用從0開始的數值做爲索引。
預約義變量ARGC初始時是ARGV數組的長度,即命令行參數的數量。
ARGV數組的數量和ARGC的值只有在awk剛開始運行的時候是保證相等的。
[root@lgh test]# awk 'BEGIN{print ARGC;for(i in ARGV){print "ARGV[" i "]= " ARGV[i]}}' a b c 4 ARGV[0]= awk ARGV[1]= a ARGV[2]= b ARGV[3]= c
awk的全部代碼(目前這麼認爲)都是寫在語句塊中的。
每一個語句塊前面能夠有pattern,好比:pattern1{action1}pattern2{action3;action4;...}
語句塊可分爲3類:BEGIN語句塊、END語句塊和main語句塊。其中BEGIN語句塊和END語句塊都是的格式分別爲BEGIN{...}和END{...},而main語句塊是一種統稱,它的pattern部分沒有固定格式,也能夠省略,main代碼塊是在讀取文件的每一行的時候都執行的代碼塊。
BEGIN代碼塊:
在讀取文件以前執行,且執行一次
在BEGIN代碼塊中,沒法使用$0或其它一些特殊變量
main代碼塊:
讀取文件時循環執行,(默認狀況)每讀取一行,就執行一次main代碼塊
main代碼塊可有多個
END代碼塊:
在讀取文件完成以後執行,且執行一次
有END代碼塊,必有要讀取的數據(能夠是標準輸入)
END代碼塊中可使用$0等一些特殊變量,只不過這些特殊變量保存的是最後一輪awk循環的數據
[root@lgh test]# awk 'BEGIN{print "hello word"}/^1/{print $0}END{print "END hello word"}' test.txt hello word 1 zhangs female 34 aaa@163.com 13423394013
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803 END hello word
實例如上:begin和end均只輸出一次,main代碼中匹配1開頭的行並輸出
$ # $(2+2) ++ --
^ **
+ - ! # 一元運算符 * / %
+ - space # 這是字符鏈接操做 `12 " " 23` `12 " " -23` | |&
< > <= >= != == # 注意>便是大於號,也是print/printf的重定向符號 ~ !~
in
&&
||
?: = += -= *= /= %= ^=
&& 邏輯與 || 邏輯或 ! 邏輯取反 expr1 && expr2 # 若是expr1爲假,則不用計算expr2 expr1 || expr2 # 若是expr1爲真,則不用計算expr2 # 注: # 1. && ||會短路運算 # 2. !優先級高於&&和|| # 因此`! expr1 && expr2`等價於`(! expr1) && expr2`
輸出格式:print elem1,elem2,elem3...
逗號分隔要打印的字段列表,各字段都會自動轉換成字符串格式,而後經過預約義變量OFS值(其默認值爲空格)鏈接各字段進行輸出
在print輸出時會自動在尾部加上輸出記錄分隔符,輸出記錄分隔符的預約義變量爲ORS,其默認值爲\n
sprintf()採用和printf相同的方式格式化字符串,可是它不會輸出格式化後的字符串,而是返回格式化後的字符串。因此,能夠將格式化後的字符串賦值給某個變量。
[root@lgh test]# awk 'BEGIN{var=sprintf("%.3f",3.141592678);print var}' #使用sprintf進行格式化複製變量,而後輸出
3.142 [root@lgh test]# awk 'BEGIN{var=sprintf("%d",3.141592678);print var}'
3 [root@lgh test]# awk 'BEGIN{OFMT="%.3f";print 3.141592678}' #使用OFMT指定格式進行輸出
3.142 [root@lgh test]# awk 'BEGIN{OFMT="%d";print 3.141592678}'
3
重定向:
>filename時,若是文件不存在,則建立,若是文件存在則首先截斷。以後再輸出到該文件時將再也不截斷。
>>filename時,將追加數據,文件不存在時則建立。
awk中只要不close(),任何文件都只會在第一次使用時打開,以後都不會再從新打開。
[root@lgh test]# awk '{print $1,$2 > "name.txt"}' test.txt #重定向到name.txt文件 [root@lgh test]# cat name.txt ID name 1 zhangs 2 lisi 3 wmzi 4 wangw 5 liub 6 zhangf 7 guany 8 zhaoy 9 huangz 10 lvbu 11 sunwk
awk數組特性:
數組的訪問和賦值都是經過制定下標就行賦值和訪問,下標能夠爲整數,負數,字符串,小數
例如:
[root@lgh test]# cat a.awk { arr[i]="a" arr[-1]="b" print arr[i] print arr[-1] print length(arr) print arr[1] #輸出不存在的數組下標內容 print "################" print length(arr) #長度+1 } [root@lgh test]# echo 0 | awk -f a.awk a b 2 ################ 3
數組遍歷、刪除、判讀某key是否在arr中:
[root@lgh test]# cat a.awk { arr["x"]="a" arr[-1]="b" arr[4.5]=1 arr[4]=5
for(idx in arr){ #遍歷 print arr[idx] } print "###############" delete arr[4] #刪除元素,也能夠刪除整個數組delete arr for(idx in arr){ #遍歷無序,與創建數組時輸入的元素順序不必定一致 print idx,arr[idx] } print "##############" print (-1 in arr) #判斷key=-1,是否在數組中,是返回1,不是返回0 print (99 in arr) } [root@lgh test]# echo 0 | awk -f a.awk 5 b a 1 ############### -1 b x a 4.5 1 ############## 1
0
if判斷:
if(condition){statement } if(condition){statement }else{statement } if(condition){statement }else if(condition){statement }else{statement }
三目運算
expr1 ? expr2 : expr3
switch選擇:
switch (expression) { case value1|regex1 : statements1 case value2|regex2 : statements2 case value3|regex3 : statements3 ... [ default: statement ] }
[root@lgh test]# awk 'NR>1{$1>5? var="B": var="A";print $1,var}' test.txt 1 A 2 A 3 A 4 A 5 A 6 B 7 B 8 B 9 B 10 B 11 B [root@lgh test]# awk 'NR>1{if($1<5){print $1,"A"}else{print $1,"B"}}' test.txt 1 A 2 A 3 A 4 A 5 B 6 B 7 B 8 B 9 B 10 B 11 B
while和do…while
while(condition){ statements } do { statements } while(condition)
for循環
for (expr1; expr2; expr3) { statement } for (idx in array) { statement }
awk '{i=1;while(i<=NF){print $i;i++}}' test.txt awk '{for(i=1;i<=NF;i++) print $i}' test.txt
break:break可退出for、while、do…while、switch語句。
continue:continue可以讓for、while、do…while進入下一輪循環。
next:next會在當前語句處當即中止後續操做,並讀取下一行,進入循環頂部。
nextfile:nextfile會在當前語句處當即中止後續操做,並直接讀取下一個文件,並進入循環頂部。
exit:直接退出awk程序,注意,END語句塊也是exit操做的一部分,因此在BEGIN或main段中執行exit操做,也會執行END語句塊。若是真的想直接退出整個awk,則能夠先設置一個flag變量,而後在END語句塊的開頭檢查這個變量再exit。
[root@lgh test]# awk 'NR==3{next}{print $0}' test.txt #匹配到了第3行,而後跳過 ID name gender age email phone 1 zhangs female 34 aaa@163.com 13423394013
3 wmzi female 61 ccc@sohu.com 18848796505
4 wangw female 31 acc@sohu.com 18848796506
5 liub male 56 gdd@163.com 18848796507
6 zhangf female 34 adb@139.com 18848796573
7 guany male 56 eab@189.com 17048796508
8 zhaoy female 35 189@163.com 17058796503
9 huangz male 65 dd@189.com 13648796593
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803 [root@lgh test]# awk 'NR==3{nextfile}{print $0}' test.txt test.txt #匹配到第3行,跳過該文件,執行下一個文件 ID name gender age email phone 1 zhangs female 34 aaa@163.com 13423394013 ID name gender age email phone 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523
3 wmzi female 61 ccc@sohu.com 18848796505
4 wangw female 31 acc@sohu.com 18848796506
5 liub male 56 gdd@163.com 18848796507
6 zhangf female 34 adb@139.com 18848796573
7 guany male 56 eab@189.com 17048796508
8 zhaoy female 35 189@163.com 17058796503
9 huangz male 65 dd@189.com 13648796593
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803
[root@lgh test]# awk 'BEGIN{ print "hello work";exit}END{print "god job"}' #默認會執行END中的代碼 hello work god job [root@lgh test]# awk 'BEGIN{ print "hello work";;exit flag=1}END{if(flag) exit ;print "god job"}' #使用flag跳出 hello work
awk中語句塊沒有做用域,都是全局變量(除非是函數中的形參)
變量的賦值:
能夠x=y=z=5,等價於z=5 y=5 x=5 能夠將賦值語句放在任意容許使用表達式的地方 x != (y = 1) awk 'BEGIN{print (a=4);print a}'
awk中聲明變量的位置:
在BEGIN或main或END代碼段中直接引用或賦值 使用-v var=val選項,可定義多個,必須放在awk代碼的前面 它的變量聲明早於BEGIN塊 普通變量:awk -v age=123 'BEGIN{print age}' 使用shell變量賦值:awk -v age=$age 'BEGIN{print age}' 在awk代碼後面使用var=val參數 它的變量聲明在BEGIN以後 awk '{print n}' n=3 a.txt n=4 b.txt awk '{print $1}' FS=' ' a.txt FS=":" /etc/passwd 使用Shell變量賦值:awk '{print age}' age=$age a.txt
使用function關鍵字來定義函數:
function func_name([parameters]){
function_body
}
函數能夠定義的位置:
awk '_ BEGIN{} _ MAIN{} _ END{} _' #能夠定義在任何下劃線的地方
[root@lgh test]# cat a.awk BEGIN{ f() } function f(){ print "自定義函數" } {}#main END{} [root@lgh test]# echo 0 | awk -f a.awk 自定義函數 [root@lgh test]# vim a.awk [root@lgh test]# cat a.awk function f(){ print "自定義函數" } BEGIN{ f() } {}#main END{} [root@lgh test]# echo 0 | awk -f a.awk 自定義函數 [root@lgh test]# vim a.awk [root@lgh test]# cat a.awk BEGIN{ f() } {}#main END{} function f(){ print "自定義函數" } [root@lgh test]# echo 0 | awk -f a.awk 自定義函數
帶參數和return的自定義函數:
[root@lgh test]# cat a.awk BEGIN{ print f(1,2) } {}#main END{} function f(a,b){ print "自定義函數"
return a+b } [root@lgh test]# echo 0 | awk -f a.awk 自定義函數 3
參數的傳遞形式:
傳遞普通變量時,是按值拷貝傳遞
傳遞數組時,是按引用傳遞
awk變量做用域:
[root@lgh test]# cat a.awk BEGIN{ a=50 #全局 print a #50 print f(a,2) #42 print a #50 } {}#main END{} function f(a,b){ print "自定義函數" a=40 #覆蓋了全局變量a print "局部",a return a+b #40+2 } [root@lgh test]# echo 0 | awk -f a.awk 50 自定義函數 局部 40
42
50
getline函數用於從文件、標準輸入或管道中讀取數據,並按狀況設置變量的值。getline能夠自動不斷的加載下一行。若是能讀取記錄,則getline的返回值爲1,遇到輸入流的尾部時,返回值爲0,不能讀取記錄(如文件沒有讀取權限、文件不存在)時,返回值爲「-1"。
其中:
getline與netx的區別
getline:讀取下一行以後,繼續執行getline後面的代碼
next:讀取下一行,當即回頭awk循環的頭部,不會再執行next後面的代碼
[root@lgh test]# awk '/^1/{print;getline;print}' test.txt #匹配1開頭的行,在1開頭的時候,獲取到了下一行,也打印了出來 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803 [root@lgh test]# awk '/^1/{print;getline;print;exit}' test.txt #執行了getline,print,而後exit了 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523 [root@lgh test]# awk '/^1/{print;if((getline var)<0)exit;print var}' test.txt #getline賦值給了var 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803 [root@lgh test]# awk '/^1/{print;if((getline var)<0)exit;print $0}' test.txt #getline賦值給了var,可是沒有設置$0 1 zhangs female 34 aaa@163.com 13423394013
1 zhangs female 34 aaa@163.com 13423394013
10 lvbu male 43 byy@sohu.com 18148796803
10 lvbu male 43 byy@sohu.com 18148796803
[root@lgh test]# awk '/^2/{while((getline var <"a.awk")>0)print var;close("a.awk")}' test.txt #匹配2開頭的行,只有一行,因此後面只執行一次,把a.awk裏面的內容賦值給var變量,而後輸出 BEGIN{ a=50 print a print f(a,2) print a } {}#main END{} function f(a,b){ print "自定義函數" a=40 print "局部",a return a+b } [root@lgh test]# awk '/^2/{while((getline<"a.awk")>0){print};close("a.awk")}' test.txt #匹配2開頭的行,只有一行,因此只執行一次,輸出a.awk中的內容 BEGIN{ a=50 print a print f(a,2) print a } {}#main END{} function f(a,b){ print "自定義函數" a=40 print "局部",a return a+b }
[root@lgh test]# awk '/^2/{"date"|getline;print}' test.txt #使用linux的date命令,經過管道,使用getline讀取 Tue Nov 24 19:44:28 CST 2020 [root@lgh test]# awk '/^2/{"date"|getline var ;print var}' test.txt Tue Nov 24 19:44:41 CST 2020 [root@lgh test]# awk '/^1/{"date"|getline var ;print var}' test.txt Tue Nov 24 19:44:48 CST 2020 Tue Nov 24 19:44:48 CST 2020 Tue Nov 24 19:44:48 CST 2020
awk雖然強大,可是有些數據仍然不方便處理,這時可將數據交給Shell命令去幫助處理,而後再從Shell命令的執行結果中取回處理後的數據繼續awk處理。awk經過|&符號來支持coproc。
awk_print[f] "something" |& Shell_Cmd Shell_Cmd |& getline [var]
這表示awk經過print輸出的數據將傳遞給Shell的命令Shell_Cmd去執行,而後awk再從Shell_Cmd的執行結果中取回Shell_Cmd產生的數據
[root@lgh test]# cat a.awk BEGIN{ CMD="sed -nr \"s/.*@(.*)$/\\1/p\""; #獲取郵箱@符號後面的內容 } NR>1{ print $5; #輸出郵箱名 print $5 |& CMD; #截取郵箱@符號後面的內容 close(CMD,"to"); CMD |& getline email_domain; #把郵箱@後面的內容賦值給變量email_domain close(CMD); print email_domain; #輸出email_domain } [root@lgh test]# awk -f a.awk test.txt aaa@163.com 163.com abb@gmail.com gmail.com ccc@sohu.com sohu.com acc@sohu.com sohu.com gdd@163.com 163.com adb@139.com 139.com eab@189.com 189.com 189@163.com 163.com dd@189.com 189.com byy@sohu.com sohu.com suk@sohu.com sohu.com
index(str1,str2):返回子串str2在字符串str1中第一次出現的位置。若是沒有指定str1,則返回0。 length(str1):返回字符串str1的長度。若是未給定str1,則表示計算"$0"的長度。 substr(str1,p):返回str1中從p位置開始的後綴字符串。 substr(str1,p,n):返回str1中從p位置開始,長度爲n的子串。 match(str1,regexp):若是regexp能匹配str1,則返回匹配起始位置。不然返回0。它會設置內置變量RSTART和RLENGTH的值。 split(str1,array,sep):使用字段分隔符sep將str1分割到數組array中,並返回數組的元素個數。若是未指定sep則採用FS的值。所以該函數用於切分字段到數組中,下標從1開始。 sprintf(fmt,expr):根據printf的格式fmt,返回格式化後的expr。 sub(regexp,rep,str2):將str2中第一個被regexp匹配的字符串替換成rep,替換成功則返回1(表示替換了1次),不然返回0。注意是貪婪匹配。 sub(regexp,rep):將"$0"中第一個被regexp匹配的字符串替換成rep,替換成功則返回1,不然返回0。注意是貪婪匹配。 gsub(regexp,rep,str2):將str2中全部被regexp匹配的內容替換成rep,並返回替換的次數。 gsub(regexp,rep):將"$0"中全部被regexp匹配的內容替換成rep,並返回替換的次數。 toupper(str):將str轉換成大寫字母,並返回新串。 tolower(str):將str轉換成小寫字母,並返回新串。
int(expr) 截斷爲整數:int(123.45)和int("123abc")都返回123,int("a123")返回0 sqrt(expr) 返回平方根 rand() 返回[0,1)之間的隨機數,默認使用srand(1)做爲種子值 srand([expr]) 設置rand()種子值,省略參數時將取當前時間的epoch值(精確到秒的epoch)做爲種子值
參考:
http://www.javashuo.com/article/p-bvyrznwq-br.html