一、概述
1. 產品概述:
awk是一種編程語言,用於在linux/unix下對文本和數據進行掃描與處理。數據可以來自標准輸入、文件、管道。
awk分別代表其作者姓氏的第一個字母。因為它的作者是三個人,分別是Alfred Aho、Peter Weinberger、Brian Kernighan。
實際上awk有很多種版本,如:awk、nawk、mawk、gawk、MKS awk、tawk... 這其中有開源產品也有商業產品。
目前在Linux中常用的awk編譯器版本有mawk,gawk,其中以RedHat為代表使用的是gawk,以Ubuntu為代表使用的是mawk。
gawk是GNU Project 的awk解釋器的開源代碼實現。
本文將以gawk作為講解工具。
2. 原理:
1). awk逐行掃描文件,從第一行到最後一行,尋找匹配特定模式的行,並在這些行上進行你想要的操作。
2). awk基本結構包括模式匹配(用於找到要處理的行)和處理過程(即處理動作)。
pattern {action}
# 提示:awk讀取文件內容的每一行時,將對比改行是否與給定的模式相匹配,如果匹配則執行處理過程,否則對該行不做任何處理。
如果沒有指定處理腳本,則把匹配的行顯示到標准輸出,即默認處理動作是print打印行;
如果沒有指定模式匹配,則默認匹配所有數據。
3). awk有兩個特殊的模式:BEGIN和END,他們被放置在沒有讀取任何數據之前以及在所有數據讀取完成以後執行。
3. awk流程圖:
提示:awk將文件中的每一行當作一條記錄,並將記錄分割為若干字段,默認以空格或制表符為分隔符。
如This is a test file. 將分割為5個字段,awk可以對這5個字段進行分別處理。
二、awk基本語法格式
1. 格式:
gawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
注釋:POSIX or GNU style options表示gawk支持POSIX以及GNU兩種選項;-f後接腳本文件;file表示准備處理的文檔名稱。
2. gawk支持以下選項:
-F fs
--field-separator fs
指定以fs作為輸入行的分隔符(默認分隔符為空格或制表符)
-v var=val
--assign var=val
在執行處理過程以前,設置一個變量var值為val
-f program-file
--file program-file
從腳本文件中讀取AWK指令,以取代在命令參數中輸入處理腳本
-W compat
-W traditional
--compat
--traditional
使用兼容模式運行awk,GNU擴展選項將被忽略
-W copyleft
-W copyright
--copyleft
--copyright
輸出簡短的GNU版權信息
-W dump-variables[=file]
--dump-variables[=file]
打印全局變量(變量名、類型、值)到文件中,如果沒有提供文件名,則自動輸出至名為dump-variables的文件中。
示例:[jacob@localhost ~]# awk -W dump-variables=out.txt 'x=1 {print x}' test.txt
-W exec file
--exec file
類似於-f選項,但腳本文件需要以#!開頭;另外命令行的變量將不再生效
-W help
-W usage
--help
--usage
顯示各個選項的簡短描述
3. awk程序結構
一個awk程序包含一系列的 模式 {動作指令} 或是函數定義。
模式可以是:
BEGIN
END
表達式
表達式,表達式
動作指令需要以{}引起來
4. 簡單示例:
[jacob@localhost ~]# awk '/^$/ {print "Blank line}' test.txt
備注:/^$/通過正則表達式匹配空白行,動作為打印Blank line;即test.txt如有N個空白行,awk將在屏幕打印N個Blank line。
[jacob@localhost ~]# awk '/HOSTNAME/' /etc/sysconfig/network
備注:打印包含主機名的行,因為沒有指定動作指令,默認動作為打印。
[jacob@localhost ~]# cat awk.sh
'/^$/ {print "Blank line}'
[jacob@localhost ~]# awk -f awk.sh test.txt
備注:提前編輯一個awk腳本再通過-f選項調用該腳本。
三、awk基本操作
1. 記錄與字段
awk一次從文件中讀取一條記錄,並將記錄存儲在字段變量$0中。記錄被分割為字段並存儲在$1,$2 ..., $NF中(默認使用空格或制表符為分隔符)。
內建變量NF為記錄的字段個數
示例:
[jacob@localhost ~]# echo hello the world |
>awk '{print $1,$2,$3}'
備注:讀取輸入行並輸出第一個字段,第二個字段,第三個字段。
[jacob@localhost ~]# echo hello the world |
>awk '{print $0}'
備注:讀取輸入行並輸出該行。
[jacob@localhost ~]# echo hello the world |
>awk '{print NF}'
備注:讀取輸入行並輸出該行的字段個數:3個字段。
[jacob@localhost ~]# echo hello the world |
>awk '{print $NF}'
備注:讀取輸入行並輸出該行的第三個字段,因為NF為3,所以$NF等同於取行的最後一個字段。
2. 字段分隔符
默認awk讀取數據以空格或制表符作為分隔符,但可以通過-F或FS(field separator)變量來改變分隔符。
示例:
[jacob@localhost ~]# awk -F: '{print $1}' /etc/passwd
[jacob@localhost ~]# awk 'BEGIN {FS = ":"} {print $1}' /etc/passwd
備注:以上兩個示例均將字段的分隔符改冒號(:),即以冒號為分隔符打印passwd文件的第一個字段(帳號名稱)。
注意:如果使用FS改變分隔符的話,需要在BEGIN處定義FS,因為在讀取第一行前就需要改變字段分隔符。
進階:指定多個字段分隔符(文檔內容為:hello the:word,!)
[jacob@localhost ~]# echo 'hello the:word,!' |
>awk 'BEGIN {FS="[:, ]"} {print $1,$2,$3,$4}'
3. 內置變量
以下為awk內置變量:
ARGC 命令行參數個數
FILENAME 當前輸入文檔的名稱
FNR 當前輸入文檔的當前記錄編號,尤其當有多個輸入文檔時有用
NR 輸入流的當前記錄編號
NF 當前記錄的字段個數
FS 字段分隔符
OFS 輸出字段分隔符,默認為空格
ORS 輸出記錄分隔符,默認為換行符\n
RS 輸入記錄分隔符,默認為換行符\n
示例:
[jacob@localhost ~]# cat test1.txt
This is a test file.
Welcome to Jacob's Class.
[jacob@localhost ~]#cat test2.txt
Hello the world.
Wow! I'm overwhelmed.
Ask for more.
[jacob@localhost ~]# awk '{print FNR}' test1.txt test2.txt
1
2
1
2
3
備注:輸出當前文檔的當前行編號,第一個文件兩行,第二個文件三行。
[jacob@localhost ~]# awk '{print NR}' test1.txt test2.txt
1
2
3
4
5
備注:awk將兩個文檔作為一個整體的輸入流,通過NR輸入當前行編號。
[jacob@localhost ~]# awk '{print NF}' test1.txt
5
4
備注:test1.txt文檔的第一行有5個字段,第二行有4個字段。
[jacob@localhost ~]# awk 'BEGIN {FS = ":"} {print $1}' /etc/passwd
[jacob@localhost ~]# awk '{print $1,$2,$3}' test1.txt
備注:默認print輸出時,各參數將的輸出分隔符默認為空格,所以輸出內容如下
This is a
Welcome to Jacob's
[jacob@localhost ~]# awk 'BEGIN {OFS="-"} {print $1,$2,$3}' test1.txt
備注:通過OFS將輸出分隔符設置為"-",這個print在輸出第一、二、三個字段時,中間的分隔符為"-",結果如下
This-is-a
Welcome-to-Jacob's
[jacob@localhost ~]# cat test3.txt
mail from: [email protected]
subject:hello
data:2012-07-12 17:00
content:Hello, The world.
mail from: [email protected]
subject:congregation
data:2012-07-12 08:31
content:Congregation to you.
mail from: [email protected]
subject:Test
data:2012-07-12 10:20
content:This is a test mail.
[jacob@localhost ~]# awk 'BEGIN {FS="\n"; RS=""} {print $3}' test3.txt
備注:讀取輸入數據,以空白行為記錄分隔符,即第一個空白行前的內容為第一個記錄,第一個記錄中字段分隔符為換行符。
以上awk的效果為打印所有的郵件時間,即每個記錄的第三個字段。
4. 表達式與操作符
表達式是由變量、常量、函數、正則表達式、操作符組成,awk中變量有字符變量和數字變量。如果在awk中定義的變量沒有初始化,則初始值為空字串或0。
注意:字符操作時一定記得需要加引號
1) 變量定義示例:
a="welcome to beijing"
b=12
2) 操作符(awk操作符與C語言類似)
+ 加
- 減
* 乘
/ 除
% 取余
^ 冪運算
++ 自加1
-- 自減1
+= 相加後賦值給變量(x+=9等同於x=x+9)
-= 相減後賦值給變量(x-=9等同於x=x-9)
*= 相乘後賦值給變量(x*=9等同於x=x*9)
/= 相除後賦值給變量(x/=9等同於x=x/9)
> 大於
< 小於
>= 大於等於
<= 小於等於
== 等於
!= 不等於
~ 匹配
!~ 不匹配
&& 與
|| 或
操作符簡單示例:
[jacob@localhost ~]# echo "test" | awk 'x=2 {print x+3}'
[jacob@localhost ~]# echo "test" | awk 'x=2,y=3 {print x*2, y*3}'
[jacob@localhost ~]# awk '/^$/ {print x+=1}' test.txt 備注:統計所有空白行
[jacob@localhost ~]# awk '/^$/ {x+=1} END {print x}' test.txt 備注:打印總空白行個數
[jacob@localhost ~]# awk -F: '$1~/root/ {print $3}' /etc/passwd 備注:打印root的ID號
[jacob@localhost ~]# awk -F: '$3>500 {print $1}' /etc/passwd 備注:列出計算機中ID號大於500的用戶名
四、awk條件及循環語句
1. IF條件判斷格式:
if (表達式)
動作1
else
動作2
或者if (表達式) 動作1;else 動作2
說明:如果表達式的判斷結果為真則執行動作1,否則執行動作2。
示例:(判斷boot分區可用容量小於20M時報警,否則顯示OK)
[jacob@localhost ~]# df |grep "boot" |awk '{if($4<20000) print "Alart"; else print "OK"}'
2. 循環
while (條件)
動作
x=1
while (i < 10) {
print $i
}
示例:
[jacob@localhost ~]# awk 'i=1 {} BEGIN { while (i<=10) {++i; print i}}' test.txt
do
動作
while (條件)
示例:
[jacob@localhost ~]# awk 'BEGIN { do {++x;print x} while (x<=10)}' test.txt
for (變量;條件;計數器)
動作
示例:
for (i=1;i<=10;i++)
print i
[jacob@localhost ~]# awk 'BEGIN {for(i=1;i<=10;i++) print i}' test.txt
[jacob@localhost ~]# awk 'BEGIN {for(i=10;i>=1;i--) print i}' test.txt
說明:因為以上循環語句使用的awk均使用的BEGIN模式,所以輸入文檔可以為任意文檔(無關緊要)。
3. Break與Continue
break 跳出循環
continue 終止當前循環
示例:
for (i=1; i<=10;i++) {
if (i=5)
continue
print i
}
說明:打印1-4,6-10
for (i=1; i<=10;i++) {
if (i=5)
break
print i
}
說明:僅打印1-4
五、函數
1. rand () 產生0-1之間的浮動類型的隨機數
備注:rand產生隨機數時需要通過srand()設置一個參數,否則單獨的rand()每次刪除的隨機數都是一樣的。
示例:
[jacob@localhost ~]# awk 'BEGIN {print rand(); srand(); print srand()}' test.txt
2. gsub(x,y,z) 在字串z中使用字串y替換與正則表達式x相匹配的所有字串,z默認為$0
sub(x,y,z) 在字串z中使用字串y替換與正則表達式x相匹配的第一個字串,z默認為$0
示例:
[jacob@localhost ~]# awk -F: 'gsub(/root/,"jacob",$0) {print $0}' /etc/passwd 備注:將passwd每行中所有的root修改為jacob顯示至屏幕
[jacob@localhost ~]# awk -F: 'sub(/root/,"jacob",$0) {print $0}' /etc/passwd 備注:將passwd每行中第一個root修改為jacob顯示至屏幕
sub相當於sed中的s///,gsub相當於sed中的s///g。
3. length(z) 返回字串z的長度
示例:
[jacob@localhost ~]# awk '{print length()}' test.txt 備注:顯示test.txt文檔每行的字符長度
4. gentline 從輸入中讀取下一行內容
示例:
[jacob@localhost ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
19G 3.6G 15G 21% /
/dev/sda1 99M 14M 81M 15% /boot
tmpfs 141M 0 141M 0% /dev/shm
none 140M 104K 140M 1% /var/lib/xenstored
說明:從以上命令的輸出結果可以看出,分區的剩余容量顯示在第4列,但唯獨/根分區的記錄顯示在了兩行;我們需要判斷當記錄的字段個數為1時,讀取下一行,並將該行的第3列顯示至屏幕。
[jacob@localhost ~]# df -h |awk '{if(NF==1) {getline; print $3}; if(NF==6) print $4}'
[jacob@localhost ~]# df -h |awk 'BEGIN {print "Disk Free:"} {if(NF==1) {getline; print $3}; if(NF==6) print $4}'
六、awk演示示例(源自於man手冊)
1. emulate cat. 模擬cat程序
{ print }
2. emulate wc. 模擬wc程序,統計行數、單詞數、字符數
{ chars += length($0) + 1 # add one for the \n
words += NF
}
END{ print NR, words, chars }
3. sum the second field of every record based on the first field. 根據第一列的內容統計第二列的數據
$1 ~ /credit|gain/ { sum += $2 }
$1 ~ /debit|loss/ { sum -= $2 }
END { print sum }
4. Print and sort the login names of all users: 顯示計算機帳號用戶名並排序
BEGIN { FS = ":" }
{ print $1 | "sort" }
本文出自 “丁丁歷險” 博客,請務必保留此出處http://manual.blog.51cto.com/3300438/932958