awk 編程實例解說
[root@test awk]# awk 'BEGIN{FS=":";OFS="\t";ORS="\n\n"}{print $1,$2,$3}' grade.txt
M.Tansley 05/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 26
P.Bunny 02/99 48 Yellow 12 35 28
J.Troll 07/99 4842 Brown-3 12 26 26
L.Tansley 05/99 4712 Brown-2 12 30 28
awk可以使用多個域分隔符
awk -F '[ :]' '{print $1,$2}' datafile2
awk -F '[:]+' '{print $1,$2}' datafile2
使用空格和冒號作分隔符
[root@test awk]# awk '/Marry/{count++}END{print "Marry was found " count " times."}' employees
Marry was found 1 times.
定義一個變量count,在查找到marry后,計數值加1,最后打印輸出
[root@test awk]# awk '$3 >= 1655{print $1,$2 > "employes3"}' employees
[root@test awk]# awk 'BEGIN{ "date" | getline d;print d}' filename
getline 函數作用是從標准輸入,管道或者當前正在處理的文件之外的其它輸入文件獲得輸入。
它負責從輸入獲得下一行的內容,并給NF,NR和FNR等內建變量賦值。如果得到一個記錄,getline函數就返回1,
如果到達文件末尾就返回0。如果出錯,就返回-1.
[root@test awk]# awk 'BEGIN{"date"|getline d;split(d,mon);print mon[1]" "mon[2]" "mon[3]}' filename
三 11月 4
split函數把變量d轉化為數組mon,然后打印數組mon的第1,2,3個元素
awk 'BEGIN{while ("ls" | getline) print}' a.out
命令ls輸出傳遞給getline作為輸入,循環的每一個反復,getline都從ls讀取一行輸入,并把它打印到屏幕
[root@test awk]# awk 'BEGIN{print "what is your name?" ;getline name < "/dev/tty"}
$1 ~ name {print "Found" name " on line ", NR "."}END{print "see ya," name "."}' employees
what is your name?Marry
FoundMarry on line 2.
see ya,Marry.
從終端獲昨輸入name,與文件的第1個域比較,發現相同時,輸出。
[root@test awk]# awk 'BEGIN{while (getline < "/etc/passwd" > 0)lc++;print lc}' file
407
awk將逐行讀取文件的內容,在達到文件末尾前,計數器lc一直打印,當到了末尾后,打印lc的值。
如果文件不存在,getline返回-1,到達文件的末尾返回0,讀到一行,返回1,如果文件不存在會陷入無限
死循環。
===========
管道
如果你在awk 程序中打開一個管道,那么在打開下一個管道之前必須關閉它。管道符號右邊可以通過雙引號關閉
管道。在同一時刻只能有一個管道存在。
如果你打算在awk程序中再次使用文件,管道來進行讀或者寫,則先要去關閉它,因為直到腳本結束它都不會自動關閉。
一旦打開,管道就保持開的狀態直到awk退出,所以END語句模塊中的語句對于管道也是有效的,
awk '{print $1,$2,$3|"sort -r +1 -2 +0 -1"}END{close("sort -r +1 -2 +0 -1")}' names
==========================
system函數 內建的system函數把linux命令作為參數執行這些命令,然后返回退出狀態值給awk程序。linux的命令
必須被雙引號引用。如前面的date命令。。
{
system ("cat " $1 )
system ( "clear" )
}
awk 'NR==2,NR==5{print NR,$0}' datafile
如果NR的值在2-5之間,就打印NR和第0域
===========================
練習 :以下文件,編寫一個腳本,按以下格式輸出
[haibin.xie@test ~]$ cat db
Mike Harrington:(510)548-1278:250:100:175
Christian Dobbins:(408)538-2358:155:90:201
Susan Dalsass:(206)654-6279:250:60:50
Archie McNichol:(206)548-1348:250:100:175
Jody Savage:(206)548-1278:15:188:150
Guy Quigley:(916)343-6410:250:100:175
Dan Savage:(406)298-7744:450:300:275
Nancy McNeil:(206)548-1278:250:80:75
John Goldenrod:(916)348-4278:250:100:175
Chet Main:(510)548-5258:50:95:135
Tom Savage:(408)926-3456:250:168:200
Elizabeth Stachelin:(916)440-1763:175:75:300
[haibin.xie@test ~]$ awk -f gawk.sc db
***GAMPATGN 2000 CONTRIBUTIONS***
-----------------------------------------------------------------------
NAME PHONE Jan| Feb| Mar| Total Donated
-----------------------------------------------------------------------
Mike Harrington (510)548-1278 250.00 100.00 175.00 525.00
Christian Dobbins (408)538-2358 155.00 90.00 201.00 446.00
Susan Dalsass (206)654-6279 250.00 60.00 50.00 360.00
Archie McNichol (206)548-1348 250.00 100.00 175.00 525.00
Jody Savage (206)548-1278 15.00 188.00 150.00 353.00
Guy Quigley (916)343-6410 250.00 100.00 175.00 525.00
Dan Savage (406)298-7744 450.00 300.00 275.00 1025.00
Nancy McNeil (206)548-1278 250.00 80.00 75.00 405.00
John Goldenrod (916)348-4278 250.00 100.00 175.00 525.00
Chet Main (510)548-5258 50.00 95.00 135.00 280.00
Tom Savage (408)926-3456 250.00 168.00 200.00 618.00
Elizabeth Stachelin (916)440-1763 175.00 75.00 300.00 550.00
------------------------------------------------------------------------
SUMMARY
-------------------------------------------------------------------------
[haibin.xie@test ~]$ cat gawk.sc
BEGIN {
FS=":";printf ("%50s\n%s\n%s\n%s\n","***GAMPATGN 2000 CONTRIBUTIONS***",
"-----------------------------------------------------------------------",
"NAME\t\t\tPHONE\t\tJan|\tFeb|\tMar|\tTotal Donated",
"-----------------------------------------------------------------------")}
{printf "%-20s%-13s\t%.2f\t%.2f\t%.2f\t%.2f\n",$1,$2,$3,$4,$5i,$3+$4+$5}
END {printf "%s\n%35s\n%s\n",
"------------------------------------------------------------------------",
"SUMMARY",
"-------------------------------------------------------------------------"}
=================================================================================
================================================================
注意以下各判斷語句后面沒有符號,加分號意味著這條命令到此結束。。。。。
要注意逗號與分號用在不同的位置
================================================================
if 語句
if(expression) {
statement;statement;...
}
if 語句結構是條件語句,通過條件模塊,if可以被隱含。if后面緊跟的語句必須放在括號內,如果
這些語句多于一條,那么每條語句就需要以分號表示結束﹔所有語句放在一對花括號內以便作為一個
整體執行。
awk '{if($6>20 && $6<=50){safe++;print "OK"}}' employees
awk '{if ($6 > 20)safe++;print "OK"}' filename
if/else語句
{if (expression){
statement;statement;
}
else{
statement;statement;
}
}
awk '{if ( $3 > 1690) print $1 "Too high";else print "Range is ok"}' employees
if/else else if語句
{if(expression){
statement;statement;
}
else if (expression){
statement;statement;
}
else{
statement;
}
}
語句中間的else if的花括號可以省略
awk '{if ( $3 > 1680) print $1 "Too high";else if ($3>1650) print "now is big 1680"; else print "Range is ok"}' employees
}
==========================================
while 循環
awk '{ i=1;while (i<=NF){print NF,$i;i++}}' filename
awk ;{for (i=1;i<=NF;i++)print NF,$i}' filex
NF記錄中域的個數
while循環常用于數組,賦值及打印
continue ; break 語句。與shell腳本中的意義一樣,可以用來跳出循環。
continue :跳出本次循環步,繼續下次循環
break: 跳出循環
程序控制語句
next 語句
next語句從輸入文件中讀取下一行,然后從頭開始執行awk腳本。
(In Script)
{ if ($1 ~ /Peter/){next}
else {print}
}
如果第一個域 包含Peter,awk就略過這一行,然后從輸入文件讀取下一行,腳本從頭開始執行
awk '{if ($1 ~/Jody/){next}else{print}}' db
exit語句
exit語句用于結束awk程序。它終止記錄的處理,但不會略過END模塊。可以賦予一個0-255間的數,以判斷退出狀態
如:exit(1)
===========
數組 數組的下標可以是數字或者字符
[root@test awk]# awk '{name[x++]=$2};END{for (i=0;i<=NR;i++)print i,name[i]}' employees
0 Jones
1 Adams
2 Chang
3 Black
x 默認從0開始計算,不可以賦初值,因為每條記錄都會讓awk語句從頭執行一次
[root@test awk]# awk '{id[NR]=$3};END{for(x=1;x<=NR;x++)print id[x]}' employees
4424
5346
1654
1683
=====
special for循環。。。。在for循環一旦無法發揮作用的時候,用于讀取關聯數組中的元素。當下標
是字符串或者是不連續的數字時,special for 循環就把下標作為關鍵字,訪問跟其關聯的值
{for(item in arrayname){
print arrayname[item]
}
}
awk '/^Tom/{name[NR]=$1};END{for(i=1;i<=NR;i++)print name[i]}' db
Tom
Tom
Tom
[root@test awk]# awk '/^Tom/{name[n++]=$1};END{for(i=1;i<=NR;i++)print name[i]}' db
Tom
Tom
Tommy
(多個空行)
使用特殊for循環
awk '/^Tom/{name[NR]=$1};END{for(i in name)print name[i]}' db Tom
Tom
Tommy
Tom
使用字符做下標。。,注意字符要用 雙引號 括起來
/tom/{count["tom"]++}
/mary/{count["marry"]++}
ENd{print "There are "count["tom"] "toms in the file and count["mary"] "marys in the file."}
使用域值做下標
for (index_value in array) statement
awk '{count[$2]++}END{for (name in count)print name,count[name]}'
[root@test awk]# awk '{count[$2]++}END{for(name in count)print name,count[name]}' datfile4
Arch 1
Tom 3
Eliza 2
Mary 1
[root@test awk]# cat datfile4
4234 Tom 43
4567 Arch 45
2008 Eliza 65
4571 Tom 22
3298 Eliza 21
4622 Tom 53
2345 Mary 24
count[$2]++ 對域的出現次數做計數,初始從0開始
=============
split(string,array,field seperator)
split(string,array)
split數組
[root@test awk]# awk 'BEGIN {split("3/15/2000",data,"/");print "the month is "data[1]" and the year is " data[3]}' filename
the month is 3 and the year is 2000
BEGIN應該放在花括號之外。。這個要注意。
delete 函數,該函數用于刪除數組元素
[root@test awk]# awk '{line[x++]=$2}END{for (x in line) delete line[x]}' datafile
awk 的多維數組
使用matrix[x,y]這樣來打印,其實質是通過多個索引串聯為一個靠內建變量SUBSEP分隔的字符串來實現
SUBSEP變量包含“\034”,它是一個非打印字符
如
cat numbers
1 2 3 4 5
2 3 4 5 6
6 7 8 9 10
{nf=NF
for(x=1;x<=NF;x++){
matrix[NR,x]=$x
}
}
END {for (x=1;x<=NR;x++){
for (y=1;y<=nf;y++}
printf "%d",matrix[x,y]
printf "\n"
}
}
======================================
awk 的命令行參數處理
ARGV 是awk和gawk的內建參數數組,存儲的是命令運行時獲取的參數
ARGC 是一個內建的包含命令行參數個數的變量,指的是獲取的參數的個數
[haibin.xie@test ~]$ cat agrvs
#This script is called argvs
BEGIN{
for (i=0;i
printf("argv[%d] is %s\n",i,ARGV[i])
}
printf("The number of arguments,ARGC=%d\n",ARGC)
}
[haibin.xie@test ~]$ awk -f agrvs db
argv[0] is awk
argv[1] is db
The number of arguments,ARGC=2
這個例子說明awk并不把選項作為參數
=======================================
awk 內建函數
字符串函數 sub ,gsub
sub (regular,expression,substitution string)
sub (regular expression,substitution string,target string)
awk '{sub(/mac/,"macintosh");print}' filename
awk '{sub(/mac/,"macintosh",$1);print}' filename
sub查找每條匹配的記錄并替換第一次匹配的,target string可以指定域
gsub (regular,expression,substitution string)
gsub (regular expression,substitution string,target string)
與sub命令相同,但會替換掉每條記錄中在、所有匹配的。
[root@test awk]# awk '{sub(/Tom/,"macintosh");print}' db
macintosh Jones lie sfieTom
[root@test awk]# awk '{gsub(/Tom/,"macintosh");print}' db
macintosh Jones lie sfiemacintosh
==============
index 函數
index 函數返回子字符串第一次被匹配的位置,偏移量從位置1開始
index(string,substring)
awk '{print index("hollow","low")}' db
4
length函數 length函數返回沒有參數的字符串的長度。length函數返回整個記錄中的字符數
[root@test awk]# awk '{ print length("hello")}' db
5
.......
[root@test awk]# awk '{ print length()}' db
21
18
.........
substr函數
substr函數返回從位置1開始的字符串的子字符串。如果長度給定就返回字符串的一部分﹔指定的長度超過實際長度,就
返回整個字符串。
substr(string,starting positinn)
substr(string,starting postion,length of string)
[root@test awk]# awk '{print substr("santa claus122",7,6)}' db
claus1
match函數
match函數返回在字符串中正則表達式位置的索引,如果找不到就返回0。match函數設置內建變量 RSTART 為字符串
中子字符串的開始位置,RLENGTH為到子字符串末尾的字符個數。
awk 'END{start=match("good ole USA",/[A-Z]+$/);print start}' filename
awk 'BEGIN{line="good ole USA"};END{match(line,/[A-Z]+$/);print substr(line,RSTART,RLENGTH)}' db
USA
match函數可以用來提取匹配的字符串
==========
toupper , tolower 函數
toupper 所有字母都變成大寫,非字母的字符不變
tolower 所有字母都變成小寫,非字母的字符不變
awk 'BEGIN{print toupper("linux"),tolower("BASH 2.0")}'
LINUX bash 2.0
============
split函數
使用作為第三個參數的域分隔符把字符串分割為一個數組
split (string,array,field separator)
split (string,array)
awk 'BEGIN{split("12/25/99",date,"/"};print date[2]}' filename
===========
sprintf 函數
sprintf函數返回指定格式的表達式,這個函數允許你使用printf函數的格式說明符
variable=sprintf("string with format specifiers",expr1,expr2,...)
awk '{line=sprintf("%-15s %6.2f",$1,$3);print line}' filename
[haibin.xie@test ~]$ awk -F: '{line=sprintf("%-15s %6.2f",$1,$3);print line}' db
Mike Harrington 250.00
Christian Dobbins 155.00
Susan Dalsass 250.00
Archie McNichol 250.00
Jody Savage 15.00
Guy Quigley 250.00
Dan Savage 450.00
Nancy McNeil 250.00
John Goldenrod 250.00
systime 函數 返回從1970年1月1日開始到當前時間的整秒數
strftime 函數
[haibin.xie@test ~]$ awk 'BEGIN{now=strftime("%m/%d/%y");print now}'
11/06/09
內建數學函數
atan2(x,y) y,x范圍內的余切
cos(x) 余弦函數
cxp(x) 求冪
int(x) 取整
log(x) 自然對數
rand() 隨機數
sin(x) 正弦
sqrt(x) 返回值
srand(x) x是rand函數的種子
整數函數
int 函數通過去掉浮點數的小數點的右邊部分,把浮點變為整數,這個過程沒有舍入
[haibin.xie@test ~]$ awk 'END{print int(31/3)}' db
10
rand函數,用來產生一個大于等于0而小于1的隨機數
[haibin.xie@test ~]$ awk '{print rand()}' db
沒有參數的stand函數用時間作為rand函數的種子。stand(x)則用x作為種子
隨機產生一個1-25之間的數
[haibin.xie@test ~]$ awk 'BEGIN{srand()};{print 1 + int(rand() * 25)}' db
8
23
24
srand函數為rand函數設置了新的種子,開始點是當時的時間。stand選擇了一個在0-25之間的隨機數,把它取整。
對于沒有分隔的文件,但有固定列寬的可以用截取函數
如
cat fixed
092491bd9923(415)134-8900
112990bg4567(803)234-1456
070489qr3455(415)899-1426
awk '{printf substr($0,1,6)" ";printf substr($0,7,6)" ";print substr($0,13,length)}' fixed
FIELDWIDTHS變量 如果文件中域的寬度固定,則可以使用這個變量。這個變量的值是以空格分隔的數字列表,列表中的每個數字都
表示相應的域的寬度。如果設置了變量FIELDWIDTHS,FS的值就將被忽略。
[haibin.xie@test ~]$ cat fixedfile
abc1245556
xxxyyyzzzz
[haibin.xie@test ~]$ awk 'BEGIN{FIELDWIDTHS="3 3 4"}{print $2}' fixedfile
124
yyy
多行記錄
如果有記錄用空行來分隔,域用換行符來分隔,要處理這樣的文件,應將記錄分隔符RS賦值為空,
域分隔符FS賦值為換行符。