在學習awk以前咱們應該都學過sed,grep,tr,cut等等命令,這些命令都是爲了方便咱們對Linux下文本和數據的處理,可是咱們會發現不少時候這些命令並不能一會兒就徹底解決咱們的需求,不少時候咱們都須要使用管道符結合這些命令來使用,今天我就給你們介紹一個命令awk,他就能很好的解決咱們對文本和數據處理的需求,使咱們一條命令就解決不少問題。正則表達式
awk被稱爲文本處理三劍客之一,其名稱得自於它的創始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母。實際上 AWK 的確擁有本身的語言: AWK 程序設計語言 , 三位建立者已將它正式定義爲「樣式掃描和處理語言」。它容許您建立簡短的程序,這些程序讀取輸入文件、爲數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其餘的功能。
因此說awk是一個強大的文本分析工具,相對於grep的查找,sed的編輯,awk在其對數據分析並生成報告時,顯得尤其強大。簡單來講awk就是把文件逐行的讀入,以空格爲默認分隔符將每行切片,切開的部分再進行各類分析處理。shell
語法形式
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
經常使用命令選項
-F fs fs指定輸入分隔符,fs能夠是字符串或正則表達式,如-F:
-v var=value 賦值一個用戶定義變量,將外部變量傳遞給awk
-f scripfile 從腳本文件中讀取awk命令
-m[fr] val 對val值設置內在限制,-mf選項限制分配給val的最大塊數目;-mr選項限制記錄的最大數目。這兩個功能是Bell實驗室版awk的擴展功能,在標準awk中不適用。express
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'數組
第一步:執行BEGIN{ commands }語句塊中的語句; 第二步:從文件或標準輸入(stdin)讀取一行,而後執行pattern{ commands }語句塊,它逐行掃描文件,從第一行到最後一行重複這個過程,直到文件所有被讀取完畢。 第三步:當讀至輸入流末尾時,執行END{ commands }語句塊。
BEGIN語句塊在awk開始從輸入流中讀取行以前被執行,這是一個可選的語句塊,好比變量初始化、打印輸出表格的表頭等語句一般能夠寫在BEGIN語句塊中。bash
END語句塊在awk從輸入流中讀取完全部的行以後即被執行,好比打印全部行的分析結果這類信息彙總都是在END語句塊中完成,它也是一個可選語句塊。ide
pattern語句塊中的通用命令是最重要的部分,它也是可選的。若是沒有提供pattern語句塊,則默認執行{ print },即打印每個讀取到的行,awk讀取的每一行都會執行該語句塊。函數
awk的調用有三種方式
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可選的。 input-file(s) 是待處理的文件。
在awk中,文件的每一行中,由域分隔符分開的每一項稱爲一個域。一般,在不指名-F域分隔符的狀況下,默認的域分隔符是空格。工具
2.shell腳本方式
awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
一個awk腳本一般由:BEGIN語句塊、可以使用模式匹配的通用語句塊、END語句塊3部分組成,這三個部分是可選的。任意一個部分均可以不出如今腳本中,腳本一般是被單引號或雙引號中,例如:學習
awk 'BEGIN{ i=0 } { i++ } END{ print i }' filename
awk "BEGIN{ i=0 } { i++ } END{ print i }" filenameui
3.將全部的awk命令插入一個單獨文件,而後調用
awk -f awk-script-file input-file(s)
其中,-f選項加載awk-script-file中的awk腳本,input-file(s)跟上面的命令行方式是同樣的。
咱們經過幾個簡單的示例來進一步瞭解awk的用法
[root@localhost ~]# awk '{print $0}' /etc/passwd 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 ......................................................................... [root@localhost ~]# echo 123|awk '{print "hello,awk"}' hello,awk [root@localhost ~]# awk '{print "hi"}' /etc/passwd hi hi hi hi hi hi hi hi hi .........................................................................
咱們指定/etc/passwd做爲輸出文件,執行awk時,它就會依次對/etc/passwd中的每一行執行print命令。
awk工做流程是這樣的:讀入有'\n'換行符分割的一條記錄,而後將記錄按指定的域分隔符劃分域,填充域,$0則表示全部域,$1表示第一個域,$n表示第n個域。默認域分隔符是"空白鍵" 或 "[tab]鍵",因此$1表示登陸用戶,$3表示登陸用戶ip,以此類推。如
打印/etc/passwd下全部的用戶名 [root@localhost ~]# awk -F: '{print $1}' /etc/passwd root bin daemon adm ........................................................................ 打印/etc/passwd下全部的用戶名及UID [root@localhost ~]# awk -F: '{print $1,$3}' /etc/passwd root 0 bin 1 daemon 2 ........................................................................ 以username: XXX uid: XXX格式輸出 [root@localhost ~]# awk -F: '{print "username: " $1 "\t\tuid: "$3}' /etc/passwd username: root uid: 0 username: bin uid: 1 username: daemon uid: 2 ........................................................................
變量 | 描述 |
---|---|
\$n | 當前記錄的第n個字段,字段間由FS分隔 |
\$0 | 完整的輸入記錄 |
ARGC | 命令行參數的數目 |
ARGIND | 命令行中當前文件的位置(從0開始算) |
ARGV | 包含命令行參數的數組 |
CONVFMT | 數字轉換格式(默認值爲%.6g)ENVIRON環境變量關聯數組 |
ERRNO | 最後一個系統錯誤的描述 |
FIELDWIDTHS | 字段寬度列表(用空格鍵分隔) |
FILENAME | 當前文件名 |
FNR | 各文件分別計數的行號 |
FS | 字段分隔符(默認是任何空格) |
IGNORECASE | 若是爲真,則進行忽略大小寫的匹配 |
NF | 一條記錄的字段的數目 |
NR | 已經讀出的記錄數,就是行號,從1開始 |
OFMT | 數字的輸出格式(默認值是%.6g) |
OFS | 輸出記錄分隔符(輸出換行符),輸出時用指定的符號代替換行符 |
ORS | 輸出記錄分隔符(默認值是一個換行符) |
RLENGTH | 由match函數所匹配的字符串的長度 |
RS | 記錄分隔符(默認是一個換行符) |
RSTART | 由match函數所匹配的字符串的第一個位置 |
SUBSEP | 數組下標分隔符(默認值是/034) |
示例
[root@localhost ~]# echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk '{print "Line No:"NR", No of fields:"NF, "$0="$0, "$1="$1, "$2="$2, "$3="$3}' Line No:1, No of fields:3 $0=line1 f2 f3 $1=line1 $2=f2 $3=f3 Line No:2, No of fields:3 $0=line2 f4 f5 $1=line2 $2=f4 $3=f5 Line No:3, No of fields:3 $0=line3 f6 f7 $1=line3 $2=f6 $3=f7
使用print $NF能夠打印出一行中的最後一個字段,使用$(NF-1)則是打印倒數第二個字段,其餘以此類推:
[root@localhost ~]# echo -e "line1 f2 f3\n line2 f4 f5" | awk '{print $NF}' f3 f5 [root@localhost ~]# echo -e "line1 f2 f3\n line2 f4 f5" | awk '{print $(NF-1)}' f2 f4
統計/etc/passwd:文件名,每行的行號,每行的列數,對應的完整行內容:
[root@localhost ~]# 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
統計/etc/passwd文件中的命令行參數ARGC,文件行號FNR,字段分隔符FS,一條記錄的字段數目NF,已經讀出的記錄數(默認是行號)NR
[root@localhost ~]# awk -F: 'BEGIN{printf "%4s %4s %4s %4s %4s %4s\n","FILENAME","ARGC","FNR","FS","NF","NR";printf "---------------------------------------------\n"} {printf "%4s %4s %4s %4s %4s %4s\n",FILENAME,ARGC,FNR,FS,NF,NR}' /etc/passwd FILENAME ARGC FNR FS NF NR --------------------------------------------- /etc/passwd 2 1 : 7 1 /etc/passwd 2 2 : 7 2 /etc/passwd 2 3 : 7 3
1.awk賦值運算
賦值語句運算符:= += -= *= /= %= ^= **=
例如:a+=5;等價於a=a+5
[root@localhost ~]# awk 'BEGIN{a=5;a+=5;print a}' 10
2.awk正則運算
輸出包含有root的行,並打印用戶名和UID及原行內容
[root@localhost ~]# awk -F: '/root/ {print $1,$3,$0}' /etc/passwd root 0 root:x:0:0:root:/root:/bin/bash operator 11 operator:x:11:0:operator:/root:/sbin/nologin
咱們發現找到了兩行,若是咱們想找root開頭的行就要這樣寫:awk -F: '/^root/' /etc/passwd
3.awk三目運算
[root@localhost ~]# awk 'BEGIN{a="b";print a=="b"?"ok":"err"}' ok [root@localhost ~]# awk 'BEGIN{a="b";print a=="c"?"ok":"err"}' err
三目運算其實就是一個判斷運算,若是爲真則輸出?後的內容,若是爲假則輸出:後的內容
4.awk的循環運用
if語句運用
[root@localhost ~]# awk 'BEGIN{ test=100;if(test>90){ print "vear good";} else{print "no pass";}}'
vear good
每條命令後用;結尾
while循環運用
計算從1累加到100的值
[root@localhost ~]# awk 'BEGIN{test=100;num=0;while(i<=test){num+=i; i++;}print num;}' 5050
for循環的運用
[root@localhost ~]# awk 'BEGIN{test=0;for(i=0;i<=100;i++){test+=i;}print test;}'
5050
do循環的運用
[root@localhost ~]# awk 'BEGIN{test=0;i=0;do{test+=i;i++}while(i<=100)print test;}'
5050
5.awk的數組運用
數組是awk的靈魂,處理文本中最不能少的就是它的數組處理。由於數組索引(下標)能夠是數字和字符串在awk中數組叫作關聯數組(associative arrays)。awk 中的數組沒必要提早聲明,也沒必要聲明大小。數組元素用0或空字符串來初始化,這根據上下文而定。通常而言,awk中的數組用來從記錄中收集信息,能夠用於計算總和、統計單詞以及跟蹤模板被匹配的次數等等。
顯示/etc/passwd的帳戶
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.awk字符串函數的運用
函數名 描述
sub 匹配記錄中最大、最靠左邊的子字符串的正則表達式,並用替換字符串替換這些字符串。若是沒有指定目標字符串就默認使用整個記錄。替換隻發生在第一次匹配的 時候
sub (regular expression, substitution string):
sub (regular expression, substitution string, target string)
實例:
awk '{ sub(/test/, "mytest"); print }' testfile awk '{ sub(/test/, "mytest"); $1}; print }' testfile
第一個例子在整個記錄中匹配,替換隻發生在第一次匹配發生的時候。如要在整個文件中進行匹配須要用到gsub
第二個例子在整個記錄的第一個域中進行匹配,替換隻發生在第一次匹配發生的時候。
gsub 整個文檔中進行匹配
gsub (regular expression, substitution string)
gsub (regular expression, substitution string, target string)
實例:
awk '{ gsub(/test/, "mytest"); print }' testfile awk '{ gsub(/test/, "mytest" , $1) }; print }' testfile
第一個例子在整個文檔中匹配test,匹配的都被替換成mytest。
第二個例子在整個文檔的第一個域中匹配,全部匹配的都被替換成mytest。
index 返回子字符串第一次被匹配的位置,偏移量從位置1開始
index(string, substring)
實例:
awk '{ print index("test", "mytest") }' testfile
實例返回test在mytest的位置,結果應該是3。
substr 返回從位置1開始的子字符串,若是指定長度超過實際長度,就返回整個字符串
substr( string, starting position )
substr( string, starting position, length of string )
實例:
awk '{ print substr( "hello world", 7,11 ) }'
上例截取了world子字符串。
split 可按給定的分隔符把字符串分割爲一個數組。若是分隔符沒提供,則按當前FS值進行分割
split( string, array, field separator )
split( string, array )
實例:
awk '{ split( "20:18:00", time, ":" ); print time[2] }'
上例把時間按冒號分割到time數組內,並顯示第二個數組元素18。
length 返回記錄的字符數
length( string )
length
實例:
awk '{ print length( "test" ) }' awk '{ print length }' testfile
第一個實例返回test字符串的長度。
第二個實例返回testfile文件中第條記錄的字符數。
match 返回在字符串中正則表達式位置的索引,若是找不到指定的正則表達式則返回0。match函數會設置內建變量RSTART爲字符串中子字符串的開始位 置,RLENGTH爲到子字符串末尾的字符個數。substr可利於這些變量來截取字符串
match( string, regular expression )
實例:
awk '{start=match("this is a test",/[a-z]+$/); print start}' awk '{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'
第一個實例打印以連續小寫字符結尾的開始位置,這裏是11。
第二個實例還打印RSTART和RLENGTH變量,這裏是11(start),11(RSTART),4(RLENGTH)。
toupper和tolower 可用於字符串大小間的轉換,該功能只在gawk中有效
toupper( string )
tolower( string )
實例:
awk '{ print toupper("test"), tolower("TEST") }'