Shell 學(xué)習(xí)—AWK---kiki整理
Posted on 2011-01-27 16:21 幻海藍(lán)夢 閱讀(454) 評論(0) 編輯 收藏 所屬分類: Linux 、ShellShell 學(xué)習(xí)—AWK
= = = 安裝awk
root@kiki-desktop:~/shell# apt-get install gawk gawk-doc
= = = awk 是一種程序語言. 它具有一般程序語言常見的功能.
= = =.因awk語言具有某些特點(diǎn),
如 : 使用直譯器(Interpreter)不需先行編譯;
變量無類型之分(Typeless), 可使用文字當(dāng)數(shù)組的下標(biāo)(Associative Array)...等特色. 因此, 使用awk撰寫程序比起使用其它語言更簡潔便利且節(jié)省時(shí)間.
awk還具有一些內(nèi)建功能, 使得awk擅于處理具數(shù)據(jù)行(Record), 字段(Field)型態(tài)的資料;
此外, awk內(nèi)建有pipe的功能, 可將處理中的數(shù)據(jù)傳送給外部的 Shell命令加以處理, 再將Shell命令處理后的數(shù)據(jù)傳回awk程序, 這個特點(diǎn)也使得awk程序很容易使用系統(tǒng)資源.
= = = awk程序的主要結(jié)構(gòu):
awk程序中主要語法是 Pattern { Actions}, 故常見之awk 程序其型態(tài)如下 :
Pattern1 { Actions1 }
= = = Actions 是什么?
Actions 是由許多awk指令構(gòu)成. 而awk的指令與 C 語言中的指令十分類似.
例如 :
awk的 I/O指令 : print, printf( ), getline...
awk的 流程控制指令 : if(...){..} else{..}, while(...){...}...
= = = 例子
有時(shí)語法 Pattern { Actions }中, Pattern 部分被省略,只剩 {Actions}.這種情形表示 "無條件執(zhí)行這個 Actions".
50 > 23 {print "Hello! The word!!" }
"banana" ~ /123/ { print "Good morning !" }
# awk '{print $2,$3*$4}' emp
UNIX命令行上, 執(zhí)行awk的語法為:
$awk 'awk程序' 欲處理的資料文件文件名
# cat file1 | awk -F , {'print $1,$2'}
= = = 例如 : awk 從資料文件 emp.dat 中讀入第一筆數(shù)據(jù)行
"A125 Jenny 100 210" 之后, 程序中:
$0 之值將是 "A125 Jenny 100 210"
$1 之值為 "A125"
$2 之值為 "Jenny"
$3 之值為 100
$4 之值為 210
$NF 之值為 4
$NR 之值為 1
$FILENAME 之值為 "emp.dat"
= = = awk的工作流程 :
執(zhí)行awk時(shí), 它會反復(fù)進(jìn)行下列四步驟.
自動從指定的數(shù)據(jù)文件中讀取一個數(shù)據(jù)行.
自動更新(Update)相關(guān)的內(nèi)建變量之值. 如 : NF, NR, $0...
依次執(zhí)行程序中 所有 的 Pattern { Actions } 指令.
當(dāng)執(zhí)行完程序中所有 Pattern { Actions } 時(shí), 若數(shù)據(jù)文件中還有未讀取的數(shù)據(jù), 則反復(fù)執(zhí)行步驟1到步驟4.
awk會自動重復(fù)進(jìn)行上述4個步驟, 使用者不須于程序中編寫這個循環(huán) (Loop).
= = = linux中 文本以空格分隔的行就可以默認(rèn)操作
以其他分隔如, ;等等,就可以用awk –f 操作
dengfang,0Rgbo2Kyn0hms
huyibao,0R1d4zCYO3qxk
dengfeng,0RUsQ9pz6kBPs
gongfangping,0Ru/KhW.8Ove6
liucaigeng,0Rekdi5B0sWfU
= = = print 的參數(shù)間彼此以 "," (逗號) 隔開, 印出數(shù)據(jù)時(shí)彼此間會以空白隔開.
例一,選擇符合指定條件的記錄
組裝部門員工調(diào)薪5%,(組裝部門員工之ID以"A"開頭)
所有員工最后之薪資率若仍低于100, 則以100計(jì).
編寫awk程序打印新的員工薪資率報(bào)表.
原文件:
A125 Jenny 100 210
A341 Dan 110 215
P158 Max 130 209
P148 John 125 220
A123 Linda 95 210
[root@kiki-desktop:~/shell# cat adjust1.awk
$1 ~ /^A.*/ {$3*=1.05} $3<100 {$3=100}
{printf("%s %8s %d\n",$1,$2,$3)}
root@kiki-desktop:~/shell# cat emp
A125 Jenny 100 210
A341 Dan 110 215
P158 Max 130 209
P148 John 125 220
A123 Linda 95 210
root@kiki-desktop:~/shell# awk -f adjust1.awk emp
A125 Jenny 105
100
A341 Dan 115
100
P158 Max 130
100
P148 John 125
100
A123 Linda 100
例二,統(tǒng)計(jì)各科修課人數(shù),并印出結(jié)果
此為一學(xué)生注冊的資料文件; 第一欄為學(xué)生姓名, 其后為該生所修課程.
Mary O.S. Arch. Discrete
Steve D.S. Algorithm Arch.
Wang Discrete Graphics O.S.
Lisa Graphics A.I.
Lily Discrete Algorithm
.
建立如下程序,并取名為 course.awk:
{ for( i=2; i <= NF; i++) Number[$i]++ }
END{for(course in Number) printf("%10s %d\n", course, Number[course] )}
執(zhí)行下列命令 :
$awk -f course.awk reg.dat
執(zhí)行結(jié)果如下 :
Graphics 2
O.S. 2
Discrete 3
A.I. 1
D.S. 1
Arch. 2
Algorithm 2
解說:指令中END 為awk之保留字, 為 Pattern 的一種.
END 成立(其值為true)的條件是: "awk處理完所有數(shù)據(jù), 即將離開程序時(shí). "
平常讀入數(shù)據(jù)行時(shí), END并不成立, 故其后的Actions 并不被執(zhí)行;
唯有當(dāng)awk讀完所有數(shù)據(jù)時(shí), 該Actions才會被執(zhí)行 ( 注意, 不管數(shù)據(jù)行有多少筆, END僅在最后才成立, 故該Actions僅被執(zhí)行一次.)
BEGIN 與 END 有點(diǎn)類似, 是awk中另一個保留的Pattern.
唯一不同的是: "以 BEGIN 為 Pattern 的 Actions 于程序一開始執(zhí)行時(shí), 被執(zhí)行一次."
= = = awk中數(shù)組的特性
使用字符串當(dāng)數(shù)組的下標(biāo)(index).
使用數(shù)組前不須宣告數(shù)組名及其大小.
例如: 希望用數(shù)組來記錄 reg.dat 中各門課程的修課人數(shù).
這情況,有二項(xiàng)信息必須儲存:
(a) 課程名稱, 如: "O.S.","Arch.".. ,共有哪些課程事先并不明確.
(b)各課程的修課人數(shù). 如: 有幾個人修"O.S."
在awk中只要用一個數(shù)組就可同時(shí)記錄上列信息. 其方法如下:
使用一個數(shù)組 Number[ ] :
以課程名稱當(dāng) Number[ ] 的下標(biāo).
以 Number[ ] 中不同下標(biāo)所對映的元素代表修課人數(shù).
例如:
有2個學(xué)生修 "O.S.", 則以 Number["O.S."] = 2 表之.
若修"O.S."的人數(shù)增加一人,則 Number["O.S."] = Number["O.S."] + 1 或 Number["O.S."]++ .
例三,寫一個awk程序來打印出線上人數(shù).
將下列程序建文件, 命名為 count.awk
BEGIN {
while ( "who" | getline ) n++
print n
}
并執(zhí)行下列命令 :
awk -f count.awk
執(zhí)行結(jié)果將會印出目前在線人數(shù)
getline var
pipe 變量
變量 var(var省略時(shí),表示置于$0)
例四,重定向輸出到文件
root@kiki-desktop:~/shell# cat arr.dat
1034 7:26
1025 7:27
1101 7:32
1006 7:45
1012 7:46
1028 7:49
1051 7:51
1029 7:57
1042 7:59
1008 8:01
1052 8:05
1005 8:12
root@kiki-desktop:~/shell# cat reformat1.awk
BEGIN { print " ID Number Arrival Time" > "today_rpt1"
print "===========================" > "today_rpt1"
}
{ printf(" %s %s\n", $1,$2 ) > "today_rpt1" }
root@kiki-desktop:~/shell#
root@kiki-desktop:~/shell#
root@kiki-desktop:~/shell# awk -f reformat1.awk arr.dat
root@kiki-desktop:~/shell#
= = = awk 中如何利用系統(tǒng)資源
注 : awk input 指令只有 getline 一個.
awk output 指令有 print, printf() 二個.
在a 語法中, awk所輸出的數(shù)據(jù)將轉(zhuǎn)送往 Shell , 由 Shell 的命令進(jìn)行處理.以上例而言, print 所輸出的數(shù)據(jù)將經(jīng)由 Shell 命令 "sort -k 1" 排序后再送往屏幕(stdout).
上列awk程序中, "print$1, $2" 可能反復(fù)執(zhí)行很多次, 其輸出的結(jié)果將先暫存于 pipe 中,等到該程序結(jié)束時(shí), 才會一并進(jìn)行 "sort -k 1".
須注意二點(diǎn) : 不論 print $1, $2 被執(zhí)行幾次, "sort -k 1" 的執(zhí)行時(shí)間是 "awk程序結(jié)束時(shí)",
[a. 語法] awk output 指令 | "Shell 接受的命令"
( 如 : print $1,$2 | "sort -k 1" )
例5,
root@kiki-desktop:~/shell# awk '
>
> BEGIN{
>
> system("date > date.dat")
>
> getline < "date.dat"
>
> print "Today is ", $2, $3
>
> }
>
> '
Today is Jan 26
= = = = 執(zhí)行 awk 程序的幾種方式= = = =
若欲執(zhí)行該awk程序, 來印出文件 today_rpt1 及 today_rpt2 的內(nèi)容時(shí),
必須于 UNIX 的命令行上執(zhí)行下列命令 :
方式一 awk -f mydump.awk today_rpt1 today_rpt2
方式二 awk '{print}' today_rpt1 today_rpt2第二種方式系將awk 程序直接寫在 Shell 的命令行上, 這種方式僅適合較短的awk程序.
方式三 建立如下之 shell script, 并取名為 mydisplay, $ ./mydisplay today_rpt1 today_rpt2
#!/bin/sh
# 注意以下的 awk 與 ' 之間須有空白隔開
awk '
{print}
' $*
# 注意以上的 ' 與 $* 之間須有空白隔開
例5,$ ./mydisplay #(未接任何數(shù)據(jù)文件文件名)
將會發(fā)現(xiàn): 此后鍵入的任何數(shù)據(jù)將逐行復(fù)印一份于屏幕上. 這情況不是機(jī)器當(dāng)機(jī) ! 是因?yàn)?/span>awk程序正處于執(zhí)行中. 它正按程序指示, 將讀取數(shù)據(jù)并重新dump一次; 只因執(zhí)行時(shí)未指定數(shù)據(jù)文件文件名, 故awk 便以stdin(鍵盤上的輸入)為數(shù)據(jù)來源. 讀者可利用這個特點(diǎn), 設(shè)計(jì)可與awk即時(shí)聊天的程序.
root@kiki-desktop:~/shell# ./mydisplay
kiki
kiki
kiki
kiki
mina
mina
例6,改變 awk 切割字段的方式 & 自定義函數(shù)
范例 : ] 承接 6.2 的例子, 若八點(diǎn)為上班時(shí)間, 請加注 "*"于遲到記錄之前, 并計(jì)算平均上班時(shí)間.