技.藝.道:查漏補缺之-awk和sort

一、AWK

1.簡介

AWK是一個優良的文本處理工具,Linux及Unix環境中現有的功能最強大的數據處理引擎之一。這種編程及數據操作語言(其名稱得自於它的創始人阿爾佛雷德·艾侯、彼得·溫伯格和布萊恩·柯林漢姓氏的首個字母)的最大功能取決於一個人所擁有的知識,很多事情往往都是這樣。

我們可以在linux環境中使用它來進行快速的、任意規模的數據統計分析。大到幾十G、小到隨手統計文件信息均可。

2.使用

示例數據:log.txt
1,aa a,ccc,aw qr
2,ss ss,d dd,e e e,ll l
3,0 0,98 u,kj lh,ll x,2 23,hh 
4,23 3,s ss

1)取出指定列(默認分隔符爲 空格:“ ”):awk '{print $1,$4}' log.txt

$x表示第x列。

root@ubuntu:/leonRain/test# awk '{print $1,$4}' log.txt
1 awqr
2 eee
3 kjlh
4 

2)取出指定列並格式化輸出:awk '{printf "%-3s %-18s %-3s\n",$1,$4,$1}' log.txt

{printf "%-3s %-18s %-3s\n",$1,$4,$1}:第1列與第4列隔3個空格,第4列與再一個第1列隔18個空格,最後加3個空格

root@ubuntu:/leonRain/test# awk '{printf "%-3s %-18s %-3s\n",$1,$4,$1}' log.txt
1   awqr               1  
2   eee                2  
3   kjlh               3  
4                      4  

x)使用新示例數據log2.txt:

root@ubuntu:/leonRain/test# cat log2.txt 
1,aa a,ccc,aw qr
2,ss ss,d dd,e e e,ll l
3,0 0,98 u,kj lh,ll x,2 23,hh 
4,23 3,s ss

3)指定分隔符:awk -F, '{print $1,$2}' log2.txt

“-F,”:以","爲分隔符

使用內建變量:awk 'BEGIN{FS=","} {print $1,$2}' log.txt

root@ubuntu:/leonRain/test# awk -F, '{print $1,$2}' log2.txt
1 aa a
2 ss ss
3 0 0
4 23 3

root@ubuntu:/leonRain/test# awk 'BEGIN{FS=","} {print $1,$2}' log2.txt
1 aa a
2 ss ss
3 0 0
4 23 3

4)使用多個分隔符,先使用空格分割,然後對分割結果再使用","分割。最後的分割結果在同一層。

 $ awk -F '[ ,]' '{print $1,$2,$5}' log2.txt

root@ubuntu:/leonRain/test# awk -F '[ ,]' '{print $1,$2,$5}' log2.txt
1 aa aw
2 ss dd
3 0 u
4 23 ss

5)設置 數值型 變量:(例如:設置a=1,b=8)

awk -va=1 -vb=8 '{print $1,$1+a,$1*b}' log2.txt

root@ubuntu:/leonRain/test# awk -va=1 -vb=8 '{print $1,$1+a,$1*b}' log2.txt
1,aa 2 8
2,ss 3 16
3,0 4 24
4,23 5 32

6)設置 字符(串)型 變量(例如:設置a=1,b=s)

awk -va=1 -vb=s '{print $1,$1+a,$1b}' log2.txt

root@ubuntu:/leonRain/test# awk -va=1 -vb=s '{print $1,$1+a,$1b}' log2.txt
1,aa 2 1,aas
2,ss 3 2,sss
3,0 4 3,0s
4,23 5 4,23s

7)執行awk腳本:awk -f {awk腳本} {文件名}

實例: $ awk -f cal.awk log.txt

(編寫awk腳本稍後介紹。)

8)邏輯運算:單引號中可以使用使用 條件表達式 實現過濾。

awk '$1>2' log2.txt

root@ubuntu:/leonRain/test# awk '$1>2' log2.txt
2,ss ss,d dd,e e e,ll l
3,0 0,98 u,kj lh,ll x,2 23,hh 
4,23 3,s ss

9)單引號中還可以加入{print …}來指定要打印出符合條件的數據的哪些列。

awk '$1>3 {print $1,$2,$3}' log2.txt

root@ubuntu:/leonRain/test# awk '$1>3 {print $1,$2,$3}' log2.txt
3,0 0,98 u,kj
4,23 3,s ss

10)多條件查詢,找到第一列大於3,且第三列等於“ss”的。

awk '$1>3 && $3=="ss" {print $1,$2,$3}' log2.txt

root@ubuntu:/leonRain/test# awk '$1>3 && $3=="ss" {print $1,$2,$3}' log2.txt
4,23 3,s ss

11)輸出內置函數結果值

示例數據3:

root@ubuntu:/leonRain/test# cat log3.txt 
11,222,333,444,555
12,222,332,111,444
13,123,1243,999,4
14,25,12,333,1
15,99,99,99,99
16,22,22,22,44
17,11,11,11,11

 查看這些數據的所在文件名,命令行參數的數目。。。等內容(可查表得知這些代碼對應的內置函數功能,表格在附錄2)

awk -F, 'BEGIN{printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n","FILENAME","ARGC","FNR","FS","NF","NR","OFS","ORS","RS";printf "---------------------------------------------\n"} {printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n",FILENAME,ARGC,FNR,FS,NF,NR,OFS,ORS,RS}' log3.txt

root@ubuntu:/leonRain/test# awk -F, 'BEGIN{printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n","FILENAME","ARGC","FNR","FS","NF","NR","OFS","ORS","RS";printf "---------------------------------------------\n"} {printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n",FILENAME,ARGC,FNR,FS,NF,NR,OFS,ORS,RS}' log3.txt
FILENAME ARGC  FNR   FS   NF   NR  OFS  ORS   RS
---------------------------------------------
log3.txt    2    1    ,    5    1         
    

log3.txt    2    2    ,    5    2         
    

log3.txt    2    3    ,    5    3         
    

log3.txt    2    4    ,    5    4         
    

log3.txt    2    5    ,    5    5         
    

log3.txt    2    6    ,    5    6         
    

log3.txt    2    7    ,    5    7         
    

黃色部分打印表頭,綠色部分是真正的定製結果,即格式化輸出:“FILENAME,ARGC,FNR,FS,NF,NR,OFS,ORS,RS”這些內容。

12)亦可直接在 單引號中使用

awk '{print NR,FNR,$1,$2,$3}' log3.txt

root@ubuntu:/leonRain/test# awk '{print NR,FNR,$1,$2,$3}' log.txt
1 1 1 aaa ccc
2 2 2 ssss ddd
3 3 3 00 98u
4 4 4 233 ssSSs

13)指定輸出時的字段分隔符

awk '{print $1,$2,$5}' OFS=" $ "  log3.txt

root@ubuntu:/leonRain/test# awk -F, '{print $1,$2,$5}' OFS=" $ "  log3.txt
11 $  222 $  555
12 $  222 $  444
13 $  123 $  4
14 $  25 $  1
15 $  99 $  99
16 $  22 $  44
17 $  11 $  11

14)通過正則表達式匹配,查找第二列中包含"ab"的數據,並輸出其第二和第四列。

awk '$2 ~ /a/ {print $2,$4}' log.txt

root@ubuntu:/leonRain/test# awk '$2 ~ /a/ {print $2,$4}' log.txt
aaa awqr

若指定在某列中匹配,語法爲:'$列號 ~ /匹配條件/' 例如:awk '$2 ~ /s/' log2.txt

若在整條數據中匹配,則不需要使用"~",語法爲:awk '/s/' log2.txt

awk '$2 ~ /s/ && $3 ~ /s/' log2.txt

root@ubuntu:/leonRain/test# awk '$2 ~ /s/ && $3 ~ /s/' log2.txt
4,23 3,s ss

xx)使用新的示例數據:

root@ubuntu:/leonRain/test# cat logstr.txt 
this is a dog;
This is a dog;
Are you ok?
are you OK?

15)模式取反,即利用感嘆號“!”進行條件取反

awk '$1 !~ /this/' logstr.txt 

root@ubuntu:/leonRain/test# awk '$1 !~ /this/' logstr.txt 
This is a dog;
Are you ok?
are you OK?

16)awk腳本編寫

關於 awk 腳本,我們需要注意兩個關鍵詞 BEGIN 和 END。

  • BEGIN{ 這裏面放的是執行前的語句 }
  • END {這裏面放的是處理完所有的行後要執行的語句 }
  • {這裏面放的是處理每一行時要執行的語句

樣例(取自菜鳥教程,我加了一些註釋):

示例數據(學生成績表):
	$ cat score.txt
Marry   2143 78 84 77
Jack    2321 66 78 45
Tom     2122 48 77 71
Mike    2537 87 97 95
Bob     2415 40 57 62

awk 腳本如下:

$ cat cal.awk
#!/bin/awk -f
# 運行前 定義變量,打印表頭
BEGIN {
    math = 0
    english = 0
    computer = 0
 
    printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"
    printf "---------------------------------------------\n"
}
# 運行中 規定遍歷數據時的具體操作。這裏進行的是變量與具體列的逐行累加,
# 同時輸出該行數據及一些計算值,如這裏最後輸出了一個總分 $3+$4+$5。
{
    math+=$3
    english+=$4
    computer+=$5
    printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
# 運行後 輸出計算結果
END {
    printf "---------------------------------------------\n"
    printf "  TOTAL:%10d %8d %8d \n", math, english, computer
    printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}

執行結果:

$ awk -f cal.awk score.txt
NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL
---------------------------------------------
Marry  2143     78       84       77      239
Jack   2321     66       78       45      189
Tom    2122     48       77       71      196
Mike   2537     87       97       95      279
Bob    2415     40       57       62      159
---------------------------------------------
  TOTAL:       319      393      350
AVERAGE:     63.80    78.60    70.00

17)拓展

統計文件大小:

ls -l *.txt | awk '{sum+=$5} END {print sum}'

這段命令分爲兩部分:“ls -l *.txt ”作用是查看當前所在路徑下的.txt後綴的文件信息。

“awk '{sum+=$5} END {print sum}'”作用是對出入數據的第五列進行統計,並在結束時輸出結果。

root@ubuntu:/leonRain/test# ll
total 28
drwxr-xr-x  2 root root 4096 May 27 16:20 ./
drwxr-xr-x 20 root root 4096 May 27 13:55 ../
-rw-r--r--  1 root root   84 May 27 14:41 log2.txt
-rw-r--r--  1 root root  116 May 27 15:43 log3.txt
-rw-r--r--  1 root root   54 May 27 16:20 logstr.txt
-rw-r--r--  1 root root   72 May 27 16:09 log.txt
-rwxr-xr-x  1 root root   38 May 27 14:56 tt.awk*

root@ubuntu:/leonRain/test# ls -l *.txt | awk '{sum+=$5} END {print sum}'
326

找到當前目錄中屬於root用戶的文件:

ls -l * | awk '$4 ~ /root/'

root@ubuntu:/leonRain/test# ll
total 28
drwxr-xr-x  2 root root 4096 May 27 16:20 ./
drwxr-xr-x 20 root root 4096 May 27 13:55 ../
-rw-r--r--  1 root root   84 May 27 14:41 log2.txt
-rw-r--r--  1 root root  116 May 27 15:43 log3.txt
-rw-r--r--  1 root root   54 May 27 16:20 logstr.txt
-rw-r--r--  1 root root   72 May 27 16:09 log.txt
-rwxr-xr-x  1 root root   38 May 27 14:56 tt.awk*

root@ubuntu:/leonRain/test# ls -l * | awk '$4 ~ /root/'
-rw-r--r-- 1 root root  84 May 27 14:41 log2.txt
-rw-r--r-- 1 root root 116 May 27 15:43 log3.txt
-rw-r--r-- 1 root root  54 May 27 16:20 logstr.txt
-rw-r--r-- 1 root root  72 May 27 16:09 log.txt
-rwxr-xr-x 1 root root  38 May 27 14:56 tt.awk

我們可以利用上面這種方法,將常用的linux命令與awk結合使用,即:將常用linux命令的輸出結果作爲awk的輸入數據,對結果進行過濾、統計等常規簡易操作。

附錄1.awk邏輯運算說明表

運算符

描述

= += -= *= /= %=(取模賦值) ^=(異或賦值) **=(冪賦值)

賦值

?:

C條件表達式

||

邏輯或

&&

邏輯與

~ 和 !~

匹配正則表達式和不匹配正則表達式

< <= > >= != ==

關係運算符

空格

連接

+ -

加,減

* / %

乘,除與求餘

+ - !

一元加,減和邏輯非

^ ***

求冪

++ --

增加或減少,作爲前綴或後綴

$

字段引用

in

數組成員

附錄2.awk內建變量表

變量

描述

$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)

 

二、sort

1.簡介

排序操作也是經常使用的,它可以通過sort命令實現。

2.示例

語法:sort [-bcdfimMnr][-o<輸出文件>][-t<分隔字符>][+<起始欄位>-<結束欄位>][--help][--verison][文件]

sort [-b 或 c 或 d…r均可][-o<輸出文件>][-t<分隔字符>][+<起始欄位>-<結束欄位>][--help][--verison][文件]

1)對當前目錄所有文件按大小排序。(第五列表示文件大小,因此用-k5,默認是正序排列,若需倒序可使用-rk5)

ll * | sort -n -k5
-rwxr-xr-x 1 root root  38 May 27 14:56 tt.awk*
-rw-r--r-- 1 root root  54 May 27 16:20 logstr.txt
-rw-r--r-- 1 root root  72 May 27 16:09 log.txt
-rw-r--r-- 1 root root  84 May 27 14:41 log2.txt
-rw-r--r-- 1 root root 116 May 27 15:43 log3.txt

2)對當前目錄所有文件按修改時間排序。

ll * | sort -n -k8
-rw-r--r-- 1 root root  84 May 27 14:41 log2.txt
-rwxr-xr-x 1 root root  38 May 27 14:56 tt.awk*
-rw-r--r-- 1 root root 116 May 27 15:43 log3.txt
-rw-r--r-- 1 root root  54 May 27 16:20 logstr.txt
-rw-r--r-- 1 root root  72 May 27 16:09 log.txt

3)sort還可以用來處理文件。

查看原始數據文件:

root@ubuntu:/leonRain/test# cat log.txt
1 aaa ccc awqr
2 ssss ddd eee lll
3 00 98u kjlh llx 223 hh
4 233 ssSSs

使用sort對其進行默認排序:

root@ubuntu:/leonRain/test# sort log.txt
1 aaa ccc awqr
2 ssss ddd eee lll
3 00 98u kjlh llx 223 hh
4 233 ssSSs

使用sort對其進行倒序排序:

root@ubuntu:/leonRain/test# sort -r log.txt
4 233 ssSSs
3 00 98u kjlh llx 223 hh
2 ssss ddd eee lll
1 aaa ccc awqr

使用sort按其第二列進行倒序排序:

root@ubuntu:/leonRain/test# sort -rk2 log.txt
2 ssss ddd eee lll
1 aaa ccc awqr
4 233 ssSSs
3 00 98u kjlh llx 223 hh

 

參數說明:

-b 忽略每行前面開始出的空格字符。

-c 檢查文件是否已經按照順序排序。

-d 排序時,處理英文字母、數字及空格字符外,忽略其他的字符。

-f 排序時,將小寫字母視爲大寫字母。

-i 排序時,除了040至176之間的ASCII字符外,忽略其他的字符。

-m 將幾個排序好的文件進行合併。

-M 將前面3個字母依照月份的縮寫進行排序。

-n 依照數值的大小排序。

-u 意味着是唯一的(unique),輸出的結果是去完重了的。

-o<輸出文件> 將排序後的結果存入指定的文件。

-r 以相反的順序來排序。

-t<分隔字符> 指定排序時所用的欄位分隔字符。

+<起始欄位>-<結束欄位> 以指定的欄位來排序,範圍由起始欄位到結束欄位的前一欄位。

--help 顯示幫助。

--version 顯示版本信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章