Linux三劍客之awk精講

一、awk簡介

awk不僅僅時linux系統中的一個命令,而且是一種編程語言,可以用來處理數據和生成報告(excel)。處理的數據可以是一個或多個文件,可以是來自標準輸入,也可以通過管道獲取標準輸入,awk可以在命令行上直接編輯命令進行操作,也可以編寫成awk程序來進行更爲複雜的運用。本章主要講解awk命令的運用。

二、工作原理

第一步:執行BEGIN{action;… }語句塊中的語句

第二步:從文件或標準輸入(stdin)讀取一行,然後執行pattern{ action;… }語句塊,它逐行掃描文件,從第一行到最後一行重複這個過程,直到文件全部被讀取完畢。

第三步:當讀至輸入流末尾時,執行END{action;…}語句塊BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常可以寫在BEGIN語句塊中
END語句塊在awk從輸入流中讀取完所有的行之後即被執行,比如打印所有行的分析結果這類信息彙總都是在END語句塊中完成,它也是一個可選語句塊

pattern語句塊中的通用命令是最重要的部分,也是可選的。如果沒有提供pattern語句塊,則默認執行{ print },即打印每一個讀取到的行,awk讀取的每一行都會執行該語句塊

三、awk命令格式和選項

print格式:print item1, item2, …
要點:
•(1) 逗號分隔符
•(2) 輸出的各item可以字符串,也可以是數值;當前記錄的字段、變量或awk的表達式
•(3) 如省略item,相當於print $0
示例:

awk'{print "hello,awk"}'   #打印輸出 hello ,awk 
awk –F: '{print}' /etc/passwd   #輸入全部
awk –F: ‘{print “wang”}’ /etc/passwd  #打印/etc/passwd文件中的行數的wang
awk –F: ‘{print $1}’ /etc/passwd  #打印第一列
awk –F: ‘{print $0}’ /etc/passwd  #打印全部
awk –F: ‘{print $1”\t”$3}’ /etc/passwd  #打印第一列和第三列,空格隔開
tail –3 /etc/fstab|awk‘{print $2,$4}’  #輸出文件最後三行的第二列和第四列

四、awk變量

變量:內置和自定義變量
FS:輸入字段分隔符,默認爲空白字符

awk-v FS=':' '{print $1,FS,$3}’ /etc/passwd
awk–F: '{print $1,$3,$7}’ /etc/passwd

OFS:輸出字段分隔符,默認爲空白字符

awk-v FS=‘:’ -v OFS=‘:’ '{print $1,$3,$7}’ /etc/passwd

RS:輸入記錄分隔符,指定輸入時的換行符,原換行符仍有效

awk-v RS=' ' ‘{print }’ /etc/passwd

ORS:輸出記錄分隔符,輸出時用指定符號代替換行符

awk-v RS=' ' -v ORS='###'‘{print }’ /etc/passwd

NF:字段數量

awk-F:‘{print NF}’ /etc/fstab,引用內置變量不用$
awk-F: '{print $(NF-1)}' /etc/passwd

NR:行號

awk'{print NR}' /etc/fstab; awkEND'{print NR}' /etc/fstab

FNR:各文件分別計數,行號

awk '{print FNR}' /etc/fstab /etc/inittab

FILENAME:當前文件名

awk '{print FILENAME}’ /etc/fstab

ARGC:命令行參數的個數

awk '{print ARGC}’ /etc/fstab /etc/inittab
awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab

ARGV:數組,保存的是命令行所給定的各參數

awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab
awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab

自定義變量(區分字符大小寫)

(1) -v var=value

(2) 在program中直接定義

示例:

awk-v test='hello gawk' '{print test}' /etc/fstab
awk-v test='hello gawk' 'BEGIN{print test}'
awk'BEGIN{test="hello,gawk";printtest}'
awk–F:‘{sex=“male”;print$1,sex,age;age=18}’ /etc/passwd
cat awkscript
{print script,$1,$2}
awk-F: -f awkscriptscript=“awk” /etc/passwd

五、printf命令

格式化輸出:printf“FORMAT”, item1, item2, …
(1) 必須指定FORMAT
(2) 不會自動換行,需要顯式給出換行控制符,\n
(3) FORMAT中需要分別爲後面每個item指定格式符

格式符:與item一一對應

%c: 顯示字符的ASCII碼
%d, %i: 顯示十進制整數
%e, %E:顯示科學計數法數值
%f:顯示爲浮點數
%g, %G:以科學計數法或浮點形式顯示數值
%s:顯示字符串
%u:無符號整數
%%: 顯示%自身

修飾符:

[.#]:第一個數字控制顯示的寬度;第二個#表示小數點後精度,%3.1f
-: 左對齊(默認右對齊)%-15s
+:顯示數值的正負符號%+d
示例:

•awk-F: ‘{printf"%s",$1}’ /etc/passwd
•awk-F: ‘{printf"%s\n",$1}’ /etc/passwd
•awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
•awk -F: ‘{printf "Username: %s\n",$1}’ /etc/passwd
•awk-F: ‘{printf“Username: %s,UID:%d\n",$1,$3}’
/etc/passwd
•awk-F: ‘{printf"Username: %15s,UID:%d\n",$1,$3}’
/etc/passwd
•awk-F: ‘{printf"Username: %-15s,UID:%d\n",$1,$3}’
/etc/passwd

六、操作符

邏輯操作符:與&&,或||,非!
示例:

•awk –F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
•awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
•awk -F: ‘!($3==0){print $1}' /etc/passwd
•awk -F: ‘!($3>=500) {print $3}’ /etc/passwd

函數調用:function_name(argu1, argu2, …)
條件表達式(三目表達式):
selector?if-true-expression:if-false-expression
•示例:

awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf"%15s:%-s\n",$1,usertype}' /etc/passwd

awk PATTERN

PATTERN:根據pattern條件,過濾匹配的行,再做處理
(1)如果未指定:空模式,匹配每一行
(2) /regular expression/:僅處理能夠模式匹配到的行,需要用/ /括起來

awk'/^UUID/{print $1}' /etc/fstab
awk'!/^UUID/{print $1}' /etc/fstab

(3) relational expression: 關係表達式,結果爲“真”纔會被處理
真:結果爲非0值,非空字符串
假:結果爲空字符串或0值
示例:

•awk-F: 'i=1;j=1{print i,j}' /etc/passwd
•awk‘!0’ /etc/passwd; awk‘!1’ /etc/passwd
•awk–F: '$3>=1000{print $1,$3}' /etc/passwd
•awk-F: '$3<1000{print $1,$3}' /etc/passwd
•awk-F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
•awk-F: '$NF~ /bash$/{print $1,$NF}' /etc/passwd

(4) line ranges:行範圍
startline,endline:/pat1/,/pat2/不支持直接給出數字格式

awk-F: ‘/^root\>/,/^nobody\>/{print $1}' /etc/passwd
awk-F: ‘(NR>=10&&NR<=20){print NR,$1}' /etc/passwd

(5) BEGIN/END模式
BEGIN{}: 僅在開始處理文件中的文本之前執行一次
END{}:僅在文本處理完成之後執行一次

•awk -F : 'BEGIN {print "USER USERID"} {print $1":"$3} END{print "end file"}' /etc/passwd
•awk -F : '{print "USER USERID“;print $1":"$3} END{print "end file"}' /etc/passwd
•awk -F: 'BEGIN{print " USER UID \n---------------"}{print $1,$3}' /etc/passwd
•awk -F: 'BEGIN{print " USER UID \n---------------"}{print $1,$3}'END{print "=============="} /etc/passwd
•seq 10 |awk ‘i=0’
•seq 10 |awk ‘i=1’
•seq 10 | awk 'i=!i‘
•seq 10 | awk '{i=!i;print i}‘
•seq 10 | awk ‘!(i=!i)’
•seq 10 |awk -v i=1 'i=!i'

企業面試題:統計域名訪問次數

處理以下文件內容,將域名取出並根據域名進行計數排序處理:(百度和sohu面試題)

http://www.etiantian.org/index.html
http://www.etiantian.org/1.html
http://post.etiantian.org/index.html
http://mp3.etiantian.org/index.html
http://www.etiantian.org/3.html
http://post.etiantian.org/2.html

思路:
1)以斜線爲菜刀取出第二列(域名)
2)創建一個數組
3)把第二列(域名)作爲數組的下標
4)通過類似於i++的形式進行計數
5)統計後把結果輸出

過程演示:
第一步:查看一下內容

[root@chensiqi ~]# awk -F "[/]+" '{print $2}' file 
www.etiantian.org
www.etiantian.org
post.etiantian.org
mp3.etiantian.org
www.etiantian.org
post.etiantian.org

命令說明:
這是我們需要計數的內容
第二步:計數

[root@chensiqi ~]# awk -F "[/]+" '{i++;print $2,i}' file 
www.etiantian.org 1
www.etiantian.org 2
post.etiantian.org 3
mp3.etiantian.org 4
www.etiantian.org 5
post.etiantian.org 6

命令說明:
i++:i最開始是空的,當awk讀取一行,i自身+1
第三步:用數組替換i

[root@chensiqi ~]# awk -F "[/]+" '{h[$2]++;print $2,h["www.etiantian.org"]}' file 
www.etiantian.org 1
www.etiantian.org 2
post.etiantian.org 2
mp3.etiantian.org 2
www.etiantian.org 3
post.etiantian.org 3

命令說明:
1)將i替換成h[2];h[] 2作爲我的房間號。但是目前房間裏是沒有東西的。也就是說

h[$2]=h["www.etiantian.org"] and h["post.etiantian.org"] and h["mp3.etiantian.org"] 

但是具體房間裏是沒有東西的也就是空。
2)h[$2]++就等於i++:也就是說我開始給房間里加東西;當出現同樣的東西,我就++
3)print h[“www.etiantian.org”]:意思就是說我開始要輸出了。我要輸出的是房間號爲“www.etiantian.org”裏面的內容。這裏面的內容最早是空的,隨着awk讀取每一行一旦出現房間號爲“www.etiantian.org”的房間時,我就給房間裏的內容進行++。
4)綜上,輸出的結果中,每次出現www.etiantian.org時,h[“www.etiantian.org”]就會++。因此最後的輸出數字是3
第四步:輸出最終計數結果

[root@chensiqi ~]# awk -F "[/]+" '{h[$2]++}END{for(i in h)print i,h[i]}' file 
mp3.etiantian.org 1
post.etiantian.org 2
www.etiantian.org 3
[root@chensiqi ~]# 

命令說明:
我們最終需要輸出的是去重複以後的統計結果,所以得在END模塊裏進行輸出
for(i in h)遍歷這個數組,i裏存的都是房間號
print i,h[i]:輸出每一個房間號及其房間裏的內容(計數結果)

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