一、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 顯示版本信息。