Linux三劍客之awk詳解

第一篇 awk簡介與表達式實例

  • 一種名字怪異的語言linux

  • 模式掃描和處理,處理數據和生成報告。正則表達式

awk不只僅是linux系統中的一個命令,並且是一種編程語言;它能夠用來處理數據和生成報告(excel);處理的數據能夠是一個或多個文件;能夠是直接來自標準輸入,也能夠經過管道獲取標準輸入;awk能夠在命令行上直接編輯命令進行操做,也能夠編寫成awk程序來進行更爲複雜的運用。編程

sed處理stream editor文本流,水流。數組

1、awk環境簡介

本文涉及的awk爲gawk,即GNU版本的awk。bash

[root@creditease awk]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
[root@creditease awk]# uname -r
3.10.0-862.el7.x86_64
[root@creditease awk]# ll `which awk`
lrwxrwxrwx. 1 root root 4 Nov  7 14:47 /usr/bin/awk -> gawk 
[root@creditease awk]# awk --version
GNU Awk 4.0.2
複製代碼

2、awk的格式

awk指令是由模式、動做,或者模式和動做的組合組成。編程語言

  • 模式即pattern,能夠相似理解成sed的模式匹配,能夠由表達式組成,也能夠是兩個正斜槓之間的正則表達式。好比NR==1,這就是模式,能夠把它理解爲一個條件。ide

  • 動做即action,是由在大括號裏面的一條或多條語句組成,語句之間使用分號隔開。以下awk使用格式。函數

3、記錄和域

名稱 含義
record 記錄,行
filed 域,區域,字段,列

1)NF(number of field)表示一行中的區域(列)數量,$NF取最後一個區域。工具

2)$符號表示取某個列(區域),$1,2,NF網站

3)NR (number of record) 行號,awk對每一行的記錄號都有一個內置變量NR來保存,每處理完一條記錄NR的值就會自動+1

4)FS(-F)field separator 列分隔符,以什麼把行分隔成多列

3.1 指定分隔符

[root@creditease awk]# awk -F "#" '{print $NF}' awk.txt 
GKL$123
GKL$213
GKL$321
[root@creditease awk]# awk -F '[#$]' '{print $NF}' awk.txt 
123
213
321
複製代碼

3.2 條件動做基本的條件和動做

[root@creditease awk]# cat awk.txt 
ABC#DEF#GHI#GKL$123
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
[root@creditease awk]# awk -F "#" 'NR==1{print $1}' awk.txt
ABC
複製代碼

3.3 只有條件

[root@creditease awk]# awk -F "#" 'NR==1' awk.txt
ABC#DEF#GHI#GKL$123
複製代碼

默認會有動做{print $0}

3.4 只有動做

[root@creditease awk]# awk -F "#" '{print $1}' awk.txt
ABC
BAC
CAB
複製代碼

默認處理全部行

3.5 多個模式和動做

[root@creditease awk]# awk -F "#" 'NR==1{print $NF}NR==3{print $NF}' awk.txt 
GKL$123
GKL$321
複製代碼

3.6 對$0的認識

awk中$0表示整行

[root@creditease awk]# awk '{print $0}' awk_space.txt
ABC DEF GHI GKL$123
BAC DEF GHI GKL$213
CBA DEF GHI GKL$321
複製代碼

3.7 FNR

FNR與NR相似,不過多文件記錄不遞增,每一個文件都從1開始(後邊處理多文件會講到)

[root@creditease awk]# awk '{print NR}' awk.txt awk_space.txt 
1
2
3
4
5
6
[root@creditease awk]# awk '{print FNR}' awk.txt awk_space.txt 
1
2
3
1
2
3
複製代碼

4、正則表達式與操做符

awk同sed同樣也能夠經過模式匹配來對輸入的文本進行匹配處理。 awk也支持大量的正則表達式模式,大部分與sed支持的元字符相似,並且正則表達式是玩轉三劍客的必備工具。

awk支持的正則表達式元字符

awk默認不支持的元字符,和須要添加參數才能支持的元字符

元字符 功能 示例 解釋
x{m} x重複m次 /cool{5}/ 須要注意一點的是,cool加括號或不加括號的區別,x可使字符串也能夠只是一個字符,因此/cool{5}/表示匹配coo再加上5個l,即coolllll。/(cool){2,}/表示匹配coolcool,coolcoolcool等。
x{m,} x重複至少m次 /(cool){2,}/ 同上
x{m,n} x重複至少m次,但不超過n次,須要指定參數:--posix或者--re-interval。沒有該參數不能使用這種模式 /(cool){5,6}/ 同上

正則表達式的運用,默認是在行內查找匹配的字符串,如有匹配則執行action操做,可是有時候僅須要固定的列表匹配指定的正則表達式。

好比:

我想取/etc/passwd文件中第五列($5)這一列查找匹配mail字符串的行,這樣就須要用另外兩個匹配操做符。而且awk裏面只有這兩個操做符來匹配正則表達式的。

正則匹配操做符
~ 用於對記錄或區域的表達式進行匹配。
!~ 用於表達與~相反的意思。

4.1 正則實例

1)顯示awk.txt中GHI列

[root@creditease awk]# cat awk.txt 
ABC#DEF#GHI#GKL$123
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
[root@creditease awk]# awk -F "#" '{print $3}' awk.txt 
GHI
GHI
GHI
[root@creditease awk]# awk -F "#" '{print $(NF-1)}' awk.txt 
GHI
GHI
GHI
複製代碼

2)顯示包含321的行

[root@creditease awk]# awk '/321/{print $0}' awk.txt 
CBA#DEF#GHI#GKL$321
複製代碼

3)以#爲分隔符,顯示第一列以B開頭或最後一列以1結尾的行

[root@creditease awk]# awk -F "#" '$1~/^B/{print $0}$NF~/1$/{print $0}' awk.txt 
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
複製代碼

4)以#爲分隔符,顯示第一列以B或C開頭的行

[root@creditease awk]# awk -F "#" '$1~/^B|^C/{print $0}' awk.txt 
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
[root@creditease awk]# awk -F "#" '$1~/^[BC]/{print $0}' awk.txt 
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
[root@creditease awk]# awk -F "#" '$1~/^(B|C)/{print $0}' awk.txt 
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
[root@creditease awk]# awk -F "#" '$1!~/^A/{print $0}' awk.txt 
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
複製代碼

5、比較表達式

awk是一種編程語言,可以進行更爲複雜的判斷,當條件爲真時,awk就執行相關的action,主要是在針對某一區域作出相關的判斷,好比打印成績在80分以上的,這樣就必須對這一個區域做比較判斷.

下表列出了awk可使用的關係運算符,能夠用來比較數字字符串,還有正則表達式,當表達式爲真的時候,表達式結果爲1,不然爲0,只有表達式爲真,awk才執行相關的action。

awk支持的關係運算符

運算符 含義 示例
< 小於 x>y
<= 小於或等於。 x<=y
== 等於 x==y
!= 不等於 x!=y
>= 大於或等於 x>=y
> 大於 x<y

5.1 比較表達式實例

顯示awk.txt的第2 ,3 行

NR //,//

[root@creditease awk]# awk 'NR==2{print $0}NR==3{print $0}' awk.txt 
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
[root@creditease awk]# awk 'NR>=1{print $0}' awk.txt 
ABC#DEF#GHI#GKL$123
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
[root@creditease awk]# awk '/BAC/,/CBA/{print $0}' awk.txt 
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
複製代碼

第二篇 awk模塊、變量與執行

完整awk結構圖以下:

1、BEGIN模塊

BEGIN模塊在awk讀取文件以前就執行,BEGIN模式經常被用來修改內置變量ORS,RS,FS,OFS等的值。能夠不接任何輸入文件

2、awk內置變量(預約義變量)

變量名 屬性
$0 當前記錄,一整行
$1,$2,3....a 當前記錄的第n個區域,區域間由FS分隔。
FS 輸入區域分隔符,默認是空格。field separator
NF 當前記錄中的區域個數,就是有多少列。number of field
NR 已經讀出的記錄數,就是行號,從1開始。number of record
RS 輸入的記錄分隔符默認爲換行符。record separator
OFS 輸出區域分隔符,默認也是空格。output record separator
FNR 當前文件的讀入記錄號,每一個文件從新計算。
FILENAME 當前正在處理的文件的文件名

特別提示:FS RS支持正則表達式

2.1 第一個做用: 定義內置變量

[root@creditease awk]# awk 'BEGIN{RS="#"}{print $0}' awk.txt 
ABC
DEF
GHI
GKL$123
BAC
DEF
GHI
GKL$213
CBA
DEF
GHI
GKL$321
複製代碼

2.2 第二個做用:打印標識

[root@creditease awk]# awk 'BEGIN{print "=======start======"}{print $0}' awk.txt 
=======start======
ABC#DEF#GHI#GKL$123
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
複製代碼

2.3 awk實現計算功能

[root@creditease files]# awk 'BEGIN{a=8;b=90;print a+b,a-c,a/b,a%b}'
98 8 0.0888889 8
複製代碼

3、END模塊

END在awk讀取完全部的文件的時候,再執行END模塊,通常用來輸出一個結果(累加,數組結果)。也能夠是和BEGIN模塊相似的結尾標識信息。

3.1 第一個做用:打印標識

[root@creditease awk]# awk 'BEGIN{print "=======start======"}{print $0}END{print "=======end======"}' awk.txt
=======start======
ABC#DEF#GHI#GKL$123
BAC#DEF#GHI#GKL$213
CBA#DEF#GHI#GKL$321
=======end======
複製代碼

3.2 第二個做用:累加

1)統計空行(/etc/services文件)

grep sed awk

[root@creditease awk]# grep "^$" /etc/services |wc -l
17
[root@creditease awk]# sed -n '/^$/p' /etc/services |wc -l
17
[root@creditease awk]# awk '/^$/' /etc/services |wc -l
17
[root@creditease awk]# awk '/^$/{i=i+1}END{print i}' /etc/services
17
複製代碼

2)算術題

1+2+3......+100=5050,怎麼用awk表示?

[root@creditease awk]# seq 100|awk '{i=i+$0}END{print i}'
5050
複製代碼

4、awk詳解小結

一、BEGIN和END模塊只能有一個,BEGIN{}BEGIN{}或者END{}END{}都是錯誤的。

二、找誰幹啥模塊,能夠是多個。

5、awk執行過程總結

awk執行過程:

一、命令行的賦值(-F或-V)

二、執行BEGIN模式裏面的內容

三、開始讀取文件

四、判斷條件(模式)是否成立

  • 成立則執行對應動做裏面的內容
  • 讀取下一行,循環判斷
  • 直到讀取到最後一個文件的結尾

五、最後執行END模式裏面的內容

第三篇:awk數組與語法

1、awk數組

1.1 數組結構

people[police]=110

people[doctor]=120

[root@creditease awk]# awk 'BEGIN{word[0]="credit";word[1]="easy";print word[0],word[1]}'
credit easy
[root@creditease awk]# awk 'BEGIN{word[0]="credit";word[1]="easy";for(i in word)print word[i]}'
credit
easy
複製代碼

1.2 數組分類

索 引數組:以數字爲下標
關聯數組:以字符串爲下標

1.3 awk關聯數組

現有以下文本,格式以下:即左邊是隨機字母,右邊是隨機數字, 即將相同的字母后面的數字加在一塊兒,按字母的順序輸出

a  1
b  3
c  2
d  7
b  5
a  3 
g  2
f  6
複製代碼

以$1爲下標,建立數組a[$1]=a[$1]+$2(a[$1]+=$2)而後配合END和for循環輸出結果:

[root@creditease awk]# awk '{a[$1]=a[$1]+$2}END{for(i in a)print i,a[i]}' jia.txt 
a 4
b 8
c 2
d 7
f 6
g 2
注意:for(i in a) 循環的順序不是按照文本內容的順序來處理的,排序能夠在命令後加sort排序
複製代碼

1.4 awk索引數組

以數字爲下標的數組 seq生成1-10的數字,要求只顯示計數行

[root@creditease awk]# seq 10|awk '{a[NR]=$0}END{for(i=1;i<=NR;i+=2){print a[i]}}'
1
3
5
7
9
複製代碼

seq生成1-10的數字,要求不顯示文件的後3行

[root@creditease awk]# seq 10|awk '{a[NR]=$0}END{for(i=1;i<=NR-3;i++){print a[i]}}'
1
2
3
4
5
6
7
解析:改變i的範圍便可,多用於不顯示文件的後幾行
複製代碼

1.5 awk數組實戰去重

a++ 和 ++a

[root@creditease awk]# awk 'BEGIN{print a++}'
0
[root@creditease awk]# awk 'BEGIN{print ++a}'
1
[root@creditease awk]# awk 'BEGIN{a=1;b=a++;print a,b}'
2 1
[root@creditease awk]# awk 'BEGIN{a=1;b=++a;print a,b}'
2 2

注:

都是 b = a+1

b=a++ 先把 a 的值賦予b,而後 a + 1

b=++a 先執行a+1,而後把a的值賦予b
複製代碼

對一下文本進行去重處理 針對第二列去重

[root@creditease awk]# cat qc.txt 
2018/10/20   xiaoli     13373305025
2018/10/25   xiaowang   17712215986
2018/11/01   xiaoliu    18615517895 
2018/11/12   xiaoli     13373305025
2018/11/19   xiaozhao   15512013263
2018/11/26   xiaoliu    18615517895
2018/12/01   xiaoma     16965564525
2018/12/09   xiaowang   17712215986
2018/11/24   xiaozhao   15512013263
複製代碼
解法一:
[root@creditease awk]# awk '!a[$2]++' qc.txt 
2018/10/20   xiaoli     13373305025
2018/10/25   xiaowang   17712215986
2018/11/01   xiaoliu    18615517895 
2018/11/19   xiaozhao   15512013263
2018/12/01   xiaoma     16965564525
解析:
!a[$3]++是模式(條件),命令也可寫成awk '! a[$3]=a[$3]+1{print $0}' qc.txt
a[$3]++ ,「++」在後,先取值後加一
!a[$3]=a[$3]+1:是先取a[$3]的值,比較「!a[$3]」是否符合條件(條件非0),後加1
注意:此方法去重後的結果顯示的是文本開頭開始的全部不重複的行
解法二:
[root@creditease awk]# awk '++a[$2]==1' qc.txt 
2018/10/20   xiaoli     13373305025
2018/10/25   xiaowang   17712215986
2018/11/01   xiaoliu    18615517895 
2018/11/19   xiaozhao   15512013263
2018/12/01   xiaoma     16965564525
解析:
++a[$3]==1是模式(條件),也可寫成a[$3]=a[$3]+1==1即只有當條件(a[$3]+1的結果)爲1的時候纔打印出內容
++a[$3] ,「++」在前,先加一後取值
++a[$3]==1:是先加1,後取a[$3]的值,比較「++a[$3]」是否符合條件(值爲1)
注意:此方法去重後的結果顯示的是文本開頭開始的全部不重複的行
解法三:
[root@creditease awk]# awk '{a[$2]=$0}END{for(i in a){print a[i]}}' qc.txt
2018/11/12   xiaoli     13373305025
2018/11/26   xiaoliu    18615517895
2018/12/01   xiaoma     16965564525
2018/12/09   xiaowang   17712215986
2018/11/24   xiaozhao   15512013263

解析:
注意此方法去重後的結果顯示的是文本結尾開始的全部不重複的行
複製代碼

1.6 awk處理多個文件(數組、NR、FNR)

使用awk取file.txt的第一列和file1.txt的第二列而後重定向到一個新文件new.txt中

[root@creditease awk]# cat file1.txt 
a b
c d
e f
g h
i j
[root@creditease awk]# cat file2.txt 
1 2
3 4
5 6
7 8
9 10
[root@creditease awk]# awk 'NR==FNR{a[FNR]=$1}NR!=FNR{print a[FNR],$2}' file1.txt file2.txt 
a 2
c 4
e 6
g 8
i 10
解析:NR==FNR處理的是第一個文件,NR!=FNR處理的是第二個文件.
注意:當兩個文件NR(行數)不一樣的時候,須要把行數多的放前邊.
解決方法:把行數多的文件放前邊,行數少的文件放後邊.
把輸出的結果放入一個新文件new.txt中:
[root@creditease awk]# awk 'NR==FNR{a[FNR]=$1}NR!=FNR{print a[FNR],$2>"new.txt"}' file1.txt file2.txt 
[root@creditease awk]# cat new.txt 
a 2
c 4
e 6
g 8
i 10
複製代碼

1.7 awk分析日誌文件,統計訪問網站的個數

[root@creditease awk]# cat url.txt 
http://www.baidu.com
http://mp4.video.cn
http://www.qq.com
http://www.listeneasy.com
http://mp3.music.com
http://www.qq.com
http://www.qq.com
http://www.listeneasy.com
http://www.listeneasy.com
http://mp4.video.cn
http://mp3.music.com
http://www.baidu.com
http://www.baidu.com
http://www.baidu.com
http://www.baidu.com
[root@creditease awk]# awk -F "[/]+" '{h[$2]++}END{for(i in h) print i,h[i]}' url.txt
www.qq.com 3
www.baidu.com 5
mp4.video.cn 2
mp3.music.com 2
www.crediteasy.com 3
複製代碼

2、awk簡單語法

2.1 函數sub gsub

替換功能

格式:sub(r, s ,目標) gsub(r, s ,目標)

[root@creditease awk]# cat sub.txt 
ABC DEF AHI GKL$123
BAC DEF AHI GKL$213
CBA DEF GHI GKL$321
[root@creditease awk]# awk '{sub(/A/,"a");print $0}' sub.txt 
aBC DEF AHI GKL$123
BaC DEF AHI GKL$213
CBa DEF GHI GKL$321
[root@creditease awk]# awk '{gsub(/A/,"a");print $0}' sub.txt 
aBC DEF aHI GKL$123
BaC DEF aHI GKL$213
CBa DEF GHI GKL$321
注:sub只會替換行內匹配的第一次內容;至關於sed ‘s###’
	gsub 會替換行內匹配的全部內容;至關於sed ‘s###g’
[root@creditease awk]# awk '{sub(/A/,"a",$1);print $0}' sub.txt 
aBC DEF AHI GKL$123
BaC DEF AHI GKL$213
CBa DEF GHI GKL$321
複製代碼

練習:

0001|20081223efskjfdj|EREADFASDLKJCV
0002|20081208djfksdaa|JDKFJALSDJFsddf
0003|20081208efskjfdj|EREADFASDLKJCV
0004|20081211djfksdaa1234|JDKFJALSDJFsddf
以'|'爲分隔, 現要將第二個域字母前的數字去掉,其餘地方都不變, 輸出爲:
0001|efskjfdj|EREADFASDLKJCV
0002|djfksdaa|JDKFJALSDJFsddf
0003|efskjfdj|EREADFASDLKJCV
0004|djfksdaa1234|JDKFJALSDJFsddf

方法:
awk -F '|'  'BEGIN{OFS="|"}{sub(/[0-9]+/,"",$2);print $0}' sub_hm.txt
awk -F '|'  -v OFS="|" '{sub(/[0-9]+/,"",$2);print $0}' sub_hm.txt
複製代碼

2.2 if和slse的用法

內容:

AA

BC

AA

CB

CC

AA

結果:

AA YES

BC NO YES

AA YES

CB NO YES

CC NO YES

AA YES

1) [root@creditease awk]# awk '{if($0~/AA/){print $0" YES"}else{print $0" NO YES"}}' ifelse.txt 
AA YES
BC NO YES
AA YES
CB NO YES
CC NO YES
AA YES
解析:使用ifelseif $0匹配到AA,則打印$0 "YES"else反之打印$0 " NO YES"。
2)[root@creditease awk]# awk '$0~/AA/{print $0" YES"}$0!~/AA/{print $0" NO YES"}' ifelse.txt 
AA YES
BC NO YES
AA YES
CB NO YES
CC NO YES
AA YES
解析:使用正則匹配,當$0匹配AA時,打印出YES,反之,打印出「NO YES」
複製代碼

2.3 next用法

如上題,用next來實現

next :跳過它後邊的全部代碼

[root@creditease awk]# awk '$0~/AA/{print $0" YES";next}{print $0" NO YES"}' ifelse.txt 
AA YES
BC NO YES
AA YES
CB NO YES
CC NO YES
AA YES
解析:
{print $0" NO YES"}:此動做是默認執行的,當前邊的$0~/AA/匹配,就會執行{print $0" YES";next}
由於action中有next,因此會跳事後邊的action。
若是符合$0~/AA/則打印YES ,遇到next後,後邊的動做不執行;若是不符合$0~/AA/,會執行next後邊的動做;
next前邊的(模式匹配),後邊的就不執行,前邊的不執行(模式不匹配),後邊的就執行。
複製代碼

2.4 printf不換行輸出以及next用法

printf :打印後不換行

以下文本,若是 Description:以後爲空,將其後一行內容併入此行。

Packages: Hello-1
Owner: me me me me
Other: who care?
Description:
Hello world!
Other2: don't care 想要結果: Packages: Hello-1 Owner: me me me me Other: who care? Description: Hello world! Origial-Owner: me me me me Other2: don't care
1)[root@creditease awk]# awk '/^Desc.*:$/{printf $0}!/Desc.*:$/{print $0}' printf.txt 
Packages: Hello-1
Owner: me me me me
Other: who care?
Description:Hello world!
Other2: don't care 解析:使用正則匹配,匹配到'/^Desc.*:$/,就使用printf打印(不換行),不匹配的打印出整行。
2)使用ifelse實現
[root@creditease awk]# awk '{if(/Des.*:$/){printf $0}else{print $0}}' printf.txt 
Packages: Hello-1
Owner: me me me me
Other: who care?
Description:Hello world!
Other2: don't care 3)使用next實現 [root@creditease awk]# awk '/Desc.*:$/{printf $0;next}{print $0}' printf.txt Packages: Hello-1 Owner: me me me me Other: who care? Description:Hello world! Other2: don't care
注:可簡寫成awk '/Desc.*:$/{printf $0;next}1'
printf.txt  ## 1是pattern(模式),默認action(動做)是{print $0}
複製代碼

2.5 去重後計數按要求重定向到指定文件

文本以下,要求計算出每項重複的個數,而後把重複次數大於2的放入gt2.txt文件中,把重複次數小於等於2的放入le2.txt文件中

[root@creditease files]# cat qcjs.txt 
aaa
bbb
ccc
aaa
ddd
bbb
rrr
ttt
ccc
eee
ddd
rrr
bbb
rrr
bbb
[root@creditease awk]# awk '{a[$1]++}END{for(i in a){if(a[i]>2){print i,a[i]>"gt2.txt"}else{print i,a[i]>"le2.txt"}}}' qcjs.txt 
[root@creditease awk]# cat gt2.txt 
rrr 3
bbb 4
[root@creditease awk]# cat le2.txt 
aaa 2
ccc 2
eee 1
ttt 1
ddd 2
解析:{print },或括號中打印後可直接重定向到一個新文件,文件名用雙引號引發來。如: {print $1 >"xin.txt"}
複製代碼

3、awk需注意事項

a)NR==FNR ##不能寫成NR=FNR(=在awk中是賦值的意思)

b)NR!=FNR ##NR不等於FNR

c){a=1;a[NR]} 這樣會報錯:同一條命令中變量和數組名不能重複 d)printf 輸出的時候不換行

e){print },或括號中打印後可直接重定向到一個新文件,文件名用雙引號引發來。如: {print $1 >"xin.txt"}

f)當模式(條件)是0的時候,後邊的動做不執行,!0的時候後邊動做才執行。

做者:秦偉

來源:宜信技術學院

相關文章
相關標籤/搜索