在Linux系統中,AWK 是一個非常強大的文本處理工具,在日常統計中起到重要的作用。
[@sjs_73_194 ~]$ man awk
GAWK(1) Utility Commands GAWK(1)
NAME
gawk - pattern scanning and processing language
SYNOPSIS
gawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
gawk [ POSIX or GNU style options ] [ -- ] program-text file ...
pgawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
pgawk [ POSIX or GNU style options ] [ -- ] program-text file ...
一、內置變量
屬 性 | 說 明 |
$0 | 當前記錄行,代表一行記錄 |
$1~$n | 當前記錄的第n個字段,字段間由FS分隔 |
FS | 輸入字段分隔符,默認是空格 |
NF | 當前記錄中的字段個數,就是有多少列,一般取最後一列字段 |
NR | 已經讀出的記錄數,就是行號,從1開始 |
RS | 輸入的記錄分隔符,默認爲換行符 |
OFS | 輸出字段分隔符,默是空格 |
ORS | 輸出的記錄分隔符,默認爲換行符 |
ARGC | 命令行參數個數 |
ARGV | 命令行參數數組 |
FILENAME | 當前輸入文件的名字 |
IGNORECASE | 如果爲真,則進行忽略大小寫的匹配 |
ARGIND | 當前被處理文件的ARGV標誌符 |
CONVFMT | 數字轉換格式 %.6g |
ENVIRON | UNIX環境變量 |
ERRNO | UNIX系統錯誤消息 |
FIELDWIDTHS | 輸入字段寬度的空白分隔字符串 |
FNR | 當前記錄數 |
OFMT | 數字的輸出格式 %.6g |
RSTART | 被匹配函數匹配的字符串首 |
RLENGTH | 被匹配函數匹配的字符串長度 |
SUBSEP | \034 |
二、 變量實例
1) 常用操作
[@sjs_73_194 ~]$ awk '/^root/ {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[@sjs_73_194 ~]$
[@sjs_73_194 ~]$ awk '{if (match($0, /root/)) print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[@sjs_73_194 ~]$
2) FS 分隔符
[@sjs_73_194 ~]$ awk 'BEGIN{FS=":"} /^root/ {print $1,$NF}' /etc/passwd
root /bin/bash
[@sjs_73_194 ~]$
注: FS爲字段分隔符,默認是空格。因爲passwd裏是”:”分隔,所以需要修改默認分隔符。除此之外還可以通過-F 來分隔,如
[@sjs_73_194 ~]$ awk -F: '/^root/ {print $1,$NF}' /etc/passwd
root /bin/bash
[@sjs_73_194 ~]$
3) 記錄條數(NR,FNR)
[@sjs_73_194 ~]$ awk '{print NR, FNR}' /etc/passwd
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
11 11
... ...
4) 字段分隔符(OFS)
awk 'BEGIN{FS=":"; OFS="##"} /^root/ {print FNR, $1, $NF}' /etc/passwd
結果: 1##root##/bin/bash
注: OFS設置默認字段分隔符, FNR當前記錄行
5) 行記錄分隔符(ORS)
awk 'BEGIN{FS=":"; ORS="##"}{print FNR, $1, $NF}' /etc/passwd
結果: 1 root /bin/bash##2 daemon /bin/sh##3 bin /bin/sh##4 sys /bin/sh##5 sync /bin/sync##......
awk 'BEGIN{FS=":"; ORS="\n"}{print FNR, $1, $NF}' /etc/passwd # "/n" 是linux 中換行符
結果:
1 root /bin/bash
2 daemon /bin/sh
3 bin /bin/sh
4 sys /bin/sh
5 sync /bin/sync
.......
注: ORS默認是換行符,這裏修改爲:”##”,所有行之間用”##”分隔了
6) 參數獲取(ARGC ,ARGV)
awk 'BEGIN{FS=":"; print "ARGC="ARGC; for(k in ARGV) {print k"="ARGV[k];}}' /etc/passwd
結果:
ARGC=2
0=awk
1=/etc/passwd
注: ARGC得到所有輸入參數個數,ARGV獲得輸入參數內容是一個數組
7) 獲得傳入的文件名(FILENAME)
awk 'BEGIN{FS=":";}/^r/ {print FILENAME, "\t", $0}' /etc/passwd
結果:
/etc/passwd root:x:0:0:root:/root:/bin/bash
/etc/passwd rtkit:x:110:117:RealtimeKit,,,:/proc:/bin/false
注: FILENAME, $0-$N,NF 不能使用在BEGIN中,BEGIN中不能獲得任何與文件記錄操作的變量
8) 獲得linux環境變量(ENVIRON)
awk 'BEGIN{print ENVIRON["PATH"];}' /etc/passwd
結果: /home/homer/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
注: ENVIRON是子典型數組,可以通過對應鍵值獲得它的值,linux 環境變量還有$HOME,$PWD等,可以通過linux 命令 env 查看
9) 輸出數據格式設置(OFMT)
awk 'BEGIN{OFMT="%.3f"; print 1, 2.0, 3.1, 2/3, 123.11111111;}' /etc/passwd
結果: 1 2 3.100 0.667 123.111
注: OFMT默認輸出格式是:%.6g 保留六位小數,這裏修改OFMT會修改默認數據輸出格式,如保留三位小數
10) 按寬度指定分隔符(FIELDWIDTHS)
echo 20130108122448 | awk 'BEGIN{FIELDWIDTHS="4 2 2 2 2 3"}{print $1"-"$2"-"$3, $4":"$5":"$6}'
結果: 2013-01-08 12:24:48
注: FIELDWIDTHS其格式爲空格分隔的一串數字,用以對記錄進行域的分隔,FIELDWIDTHS="4 2 2 2 2 2"就表示$1寬度是4,$2是2,$3是2 .... 這個時候會忽略FS分隔符
11) RSTART,RLENGTH使用
awk 'BEGIN{start=match("this is 1 teststr", /[a-z]+$/); print start, RSTART, RLENGTH }'
結果: 11 11 7
awk 'BEGIN{start=match("this is a test",/^[a-z ]+$/); print start, RSTART, RLENGTH }'
結果: 0 0 -1
awk 'BEGIN{start=match("this is a test",/^[a-z ]+$/); print start, RSTART, RLENGTH }'
結果: 1 1 14 # 增加了一個空格“ ”匹配
注: RSTART 被匹配正則表達式首位置,RLENGTH 匹配字符長度,沒有找到爲-1
三、外部變量
1) 基本用法
awk 中兩個特別的表達式,BEGIN和END
這兩者都可用於pattern中,提供BEGIN和END的作用是給程序賦予 初始狀態 和 程序結束 之後執行一些掃尾的工作。
a) 任何在BEGIN之後列出的操作(在{}內),將在awk開始掃描輸入之前執行
b) 任何在END之後列出的操作,將在掃描完全部的輸入之後執行
因此,通常使用BEGIN來顯示變量和初始化變量,使用END來輸出最終結果。
示例: echo 'awk test' | awk 'BEGIN{print "start...."} {print $0} END{print "end...."}'
結果:
start....
awk test
end....
2) 獲取外部變量
格式如: awk ‘{action}’ 變量名=變量值 ,這樣傳入變量可以在action中獲得值。
示例:
test='awk test'
echo | awk '{print test}' test="$test"
結果: awk test
echo | awk test="$test" '{print test}'
結果: awk: cmd. line:1: fatal: cannot open file `{print test}' for reading (No such file or directory)
注:變量名與值放到’{action}’後面,即 test="$test" 在 print 後面
3) BEGIN程序塊中變量
格式如:awk –v 變量名=變量值 [–v 變量2=值2 …] 'BEGIN{action}’
示例:
test='awk test'
echo | awk -v test="$test" 'BEGIN{print test}'
結果: awk test
echo | awk -v test="$test" '{print test}'
結果: awk test
注:用-v 傳入變量,可以在3中類型的action 中都可以獲得到,但順序在 action前面
4) 外部環境變量
awk 'BEGIN{for (i in ENVIRON) {print i"="ENVIRON[i];}}'
結果:
HLVL=1
PWD=/home/homer
JAVA_HOME=/home/homer/eclipse/jdk1.7.0_05
SHELL=/bin/bash
PATH=/home/homer/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
..........
注: ENVIRON是子典型數組,可以通過對應鍵值獲得它的值,linux 環境變量還有$HOME,$PWD等,可以通過linux 命令 env 查看
四、統計應用
1) match匹配
[@zw_37_232 scookie]# head tmp.log
/cesu.gif?b2386=0&b2387=128
#
[@zw_37_232 scookie]# awk '{match($0,/.+b2386=([^,]+)\&b2387=([^,]+)/,a);print a[1], a[2]}' tmp.log
0 128
[@zw_37_232 scookie]#
2) 多個文件
NR:表示awk開始執行程序後所讀取的數據行數。
FNR:awk當前讀取的記錄數,其變量值小於等於NR(比如當讀取第二個文件時,FNR是從0開始重新計數,而NR不會)。
NR==FNR:用於在讀取兩個或兩個以上的文件時,判斷是不是在讀取第一個文件。
[@zw_37_232 cesu]# head -n 1 tmp.log
710000 926
[@zw_37_232 cesu]# head -n 1 ../iploc.txt
[@zw_37_232 cesu]# head -n 3 ../iploc.txt
110000 北京市
[@zw_37_232 cesu]# awk 'NR==FNR{a[$1]=$2;next}{print $1,a[$1]}' ../iploc.txt tmp.log > sort.region.log
[@zw_37_232 cesu]# head -n 10 sort.region.log
710000 臺灣省
650000 新疆維吾爾自治區
540000 西藏自治區
530000 雲南省
810000 香港特別行政區
650000 新疆維吾爾自治區
540000 西藏自治區
520000 貴州省
650000 新疆維吾爾自治區
650000 新疆維吾爾自治區
參考推薦:
awk 實例 (IBM)