1. 程式人生 > >【Linux】awk詳細介紹

【Linux】awk詳細介紹

awk簡介

    awk是一種使用方便且表現力很強的程式語言,它可以應用在多種不同的計算與資料處理任務中。由於awk天生提供對檔案中文字分列進行處理,所以如果一個檔案中的每行都被特定的分隔符(常見的是空格)隔開,我們可以將這個檔案看成是由很多列的文字組成,這樣的檔案最適合用awk進行處理,其實awk在工作中很多時候被用來處理log檔案,進行一些統計工作等。

環境描述

檔案file1.txt,儲存了個人工作資訊,這個檔案包含名字,工作時間,每小時工資等資訊

Jack 10 12

Alice 8 13

Mary 9 20

Susie 11 10


awk程式的結構

awk都是由一個或者多個模式-動作

語句組成的序列:

pattern { action }

pattern { action }

1.awk的基本操作是由輸入行組成的序列中,陸續的掃描執行每一行,搜尋可以被模式匹配的行,每一個輸入行輪流被測試一遍,每匹配到一個模式,對應的動作就會執行,然後下一行開始,匹配重新開始,這個過程一直持續到檔案被讀取完畢為止。通常,模式是可選的,所以動作使用{}括起來,以便區分兩者。

2.命令列中的程式被單引號包圍時,這個規定可以防止程式中的字串(例如$)被shell解釋,也可以讓程式的的長度多於一行。

3.當程式的長度比較短的時候,直接寫會比較方便,但是比較長的時候,需要放到檔案中,例如檔名為pgfile

,這是隻要鍵入

awk –f pgfile

4.模式

模式中可以使用比較符>,>=,==,<,<=,!=,並且還可以使用並且與或者(&&,||)

大於(>=):awk '$2>=10 { print $1 }' file1.txt

大於(>):awk '$2>10 { print $1 }' file1.txt

等於(==):awk '$2==10 { print $1 }' file1.txt

不等於(!=):awk '$2!=10 { print $1 }' file1.txt

小於等於(<=):awk '$2<=10 { print $1 }' file1.txt


小於(<):awk '$2<10 { print $1 }' file1.txt

並且&&:awk '$2=1 && $3<10 { print $1 }' file1.txt (列印的行滿足$2>1並且$3<10)

或者||:awk '$2>11 || $3<=10 { print $1 }' file1.txt (列印的行滿足:當$2>11或者$3<=10的時候)


特殊說明

1.awk中的$1表示第一個欄位,$2表示第二個欄位,以此類推,$0表示一整行

2.awk計算當前輸入行的欄位數量,並記錄到一個內建變數NF中,因此程式{print NF}為列印輸入行欄位數量

3.awk還提供了另外一個變數NR,我們可以使用NR和$0為每一行加上行號{ print $0,NR }

4.單詞也可以用於與表示式組合;例如:awk '{ print "Total pay for",$1,"is",$2*$3 }' file1.txt

其它內建函式:

awk定義了很多內建函式,下面我們根據函式型別列出常用的函式,下面的函式只是一部分,完整的函式列表則需要查閱awk的官方文件。

算術:
atan2(y,x) 返回 y/x 的反正切。
cos(x) 返回 x 的餘弦;x 是弧度。
sin(x) 返回 x 的正弦;x 是弧度。
exp(x) 返回 x 冪函式。
log(x) 返回 x 的自然對數。
sqrt(x) 返回 x 平方根。
int(x) 返回 x 的截斷至整數的值。
rand() 返回任意數字 n,其中 0 <= n < 1。
srand([expr]) 將 rand 函式的種子值設定為 Expr 引數的值,或如果省略 Expr 引數則使用某天的時間。返回先前的種子值。
字串:
gsub(reg,str1,str2) 使用str1替換所有str2中符合正則表示式reg的子串
sub(reg,str1,str2) 含義與gsub相同,只不過gsub是替換所有匹配,sub只替換第一個匹配
index(str,substr) 返回substr在str中第一次出現的索引,注意索引從1開始計算,如果沒有則返回0
length(str) 返回str字串的長度,length函式還可以返回陣列元素的個數
blength(str) 返回字串的位元組數
match(str,reg) 與index函式一樣,只不過reg使用正則表示式,例如match("hello",/lo/)
split(str,array,reg)將str分隔成陣列儲存到array中,分隔使用正則reg,或者字串都可以,返回陣列長度
tolower(str) 轉換為小寫
toupper(str) 轉換為大寫
substr(str,start,length) 擷取字串,從start索引開始的length個字元,如不指定length則擷取到末尾,索引從1開始
其他:
system(command) 執行系統命令,返回退出碼
mktime( YYYY MM dd HH MM ss[ DST]) 生成時間格式
strftime(format,timestamp) 格式化時間輸出,將時間戳轉換為時間字串
systime() 得到時間戳,返回從1970年1月1日開始到當前時間(不計閏年)的整秒數

printf輸出

print用於簡單快速輸出,如果想要格式化輸出,可以使用printf

格式

printf(format,value1,value2…valueN)

format是一個字串,包含按字面列印的文字,中間散佈著格式說明,格式說明符用於說明如何列印。一個格式說明符是一個%,後面跟著幾個字元,這些字元控制著一個value的輸出格式。格式說明符的數量應該和列印的value一樣多

例如:

awk '{ printf("Total pay for s% is %.2f\n",$1,$2*$3) }' file1.txt

但是printf不會自動產生換行符或空格符,使用者必須自己建立。

資料驗證

awk還是一款資料驗證工具

真是的資料總數存在錯誤的,檢查資料是否有合理的值,格式是否正確,這種任務叫做資料驗證。

例如:

awk 'NF != 3 { print $0,"Number of fields is not equal to 3" }' file1.txt

BEGIN與END

特殊的模式BEGIN在第一個輸入檔案的第一行之前被匹配,END在最後一個輸入檔案的最後一行被處理之後匹配

Linux:/usr/local/sbin # echo -e '11 12 13\n21 22 23' | awk 'BEGIN{ print "col1 col2 col3";print ""}{ print $2,$1,$3 }'
col1 col2 col3

12 11 13
22 21 23

此命令將echo輸出的內容通過管道傳輸給awk,然後格式化輸出,print ""為列印單獨的空行。這裡echo命令使用了-e選項的目的就是為了保持字串中的\n的格式能夠生效,否則該換行將被忽略。

Linux:/usr/local/sbin # echo -e "1 2 3" | awk 'BEGIN{ print "begin" }{ print $1 }END{ print "end" }'
begin
1
end

awk計算

1.這個程式用於計算工作時間大於等於10h的員工數

Linux:/usr/local/sbin # awk '$2>=10 { cnt=cnt+1 }END{ print cnt,"employees worked more than 10h"}' file1.txt
2 employees worked more than 10h

此處的cnt為自定義的變數,cnt=cnt+1的意思為:每次讀取一行,如果滿足則依次加1.

2.計算員工的總報酬與平均報酬

Linux:/usr/local/sbin # awk '{ pay=pay+$2*$3 }END{ print "Total pay is ",pay ;print "Average pay is ",pay/NR }' file1.txt
Total pay is  514
Average pay is  128.5

當NR值為0的時候,則程式會報錯提示除數不為0

3.求出工作時間最長的

Linux:/usr/local/sbin # awk '$2>maxtime {maxtime=$2;maxname=$1}END{ print maxtime,maxname }' file1.txt
11 Susie

變數maxtime儲存的是數值,maxname儲存的是字串;

4.拼接字串

Linux:/usr/local/sbin # awk '{ names=names $1 "@|@"}END{ print names}' file1.txt
[email protected]|@[email protected]|@[email protected]|@[email protected]|@

此命令是將員工名字以@|@的方式進行拼接,names為初始自定義變數。

流程控制語句

if-else語句

Linux:/usr/local/sbin # echo -e '23 man Jack' | awk '{if($1<18) print "The boy is underage"; else print "The boy has group up"; }'
The boy has group up

根據孩子的年齡來判斷該孩子是否成年,成年則列印The boy has group up否則列印 The boy is underage(該孩子未成年)

while語句

while含有條件判斷和迴圈體,如果條件為真的話,迴圈體執行。

Linux:/usr/local/sbin # awk 'BEGIN{ count=1;while(count<=6){ print count;count ++}}'
1
2
3
4
5
6

count初始賦值為1,依次加1,當count超過6,則停止迴圈;

for語句

Linux:/usr/local/sbin # awk 'BEGIN{ for(i=1;i<=5;i++) print i }'
1
2
3
4
5

常用命令列

awk 'END{print NR}' file1.txt  #輸入總行數

awk 'NR==2' file1.txt            #列印第二行

awk '{print $NF}' file1.txt    #列印最後一列

awk 'NF>2' file1.txt           #列印欄位數多於2個的行

awk '$NF>12' file1.txt         #列印欄位數多於2個的行

awk '{nf=nf+NF}END{ print nf }' file1.txt  #列印輸出的欄位總個數

awk '/Su/{ line=line+1 }END{ print line}' file1.txt  #列印包含字元Su的行的數量

awk '$2>maxnum {maxnum=$2;maxname=$1}END{ print maxnum,maxname}' file1.txt  #列印$2最大值

awk 'NR>0' file1.txt  #列印至少包含一個欄位的行

awk 'length($0)>10' file1.txt  #列印長度超過10的行

awk '{ print NF,$0 }' file1.txt #每一行前新增欄位數

awk '{ print $3,$2,$1 }' file1.txt #列印每一行的欄位,但是順序相反

awk '{ $1=NR;print }' file1.txt #每一行的第一個欄位用行號替換並列印

awk '{ $2="";print }' file1.txt #列印除第二行外的其他行

案例描述

1.現在想求出每個人的當天的報酬資訊(並且每個人的工作時間必須大於0)

Linux:/usr/local/sbin # awk '$2>0 {print $1,$2*$3}' file1.txt

Jack 120
Alice 104
Mary 180
Susie 110

該命令列告訴系統執行awk程式,被執行的程式用單引號包圍起來,從file1.txt中獲取資料,被單引號包圍的是一個完整的awk程式,它由一個獨立的模式-動作組成。模式$2 > 0掃描每一個輸入行,如果該行的第二列大於0,則執行動作{print $1,$2*$3},此時就會為每一行匹配列印第一個欄位,以及第二個欄位與第三個欄位的乘積,如果想知道工作時間為0的是誰,直接使用awk '$2==0 {print $1}' file1.txt即可打印出來。


2.使用printf列印每位員工的名字與報酬

Linux:/usr/local/sbin # awk '{ printf("%-8s $%6.2f\n",$1,$2*$3) }' file1.txt
Jack     $120.00
Alice    $104.00
Mary     $180.00
Susie    $110.00

第一個格式說明符%-8s,將名字左對齊輸出,佔用8個字元寬度;第二個格式說明符%6.2f,將報酬以美元並精確小數點2位,佔用6個字元長度的方式打印出來。


3.打印出報酬,並升序排序

Linux:/usr/local/sbin # awk '{ printf("%6.2f %s\n",$2*$3,$0)}' file1.txt | sort -n
104.00 Alice 8 13
110.00 Susie 11 10
120.00 Jack 10 12
180.00 Mary 9 20

awk的輸出通過管道傳輸給sort,排序後輸出,-n是升序排序,如果需要降序排序,使用-r即可。


4.列印檔案的最後一行

Linux:/usr/local/sbin # awk '{ last=$0 }END{ print last }' file1.txt
Susie 11 10