- 論壇徽章:
- 0
|
1 awk起步
awk基本的功能是尋找那些文件中包含有特定pattern的行(或者文本單元)。當(dāng)某行匹配到其中一個pattern的時候,awk對這一行執(zhí)行指定的動作。Awk對輸入的所有行保持這種處理方式直到到達文件的末尾。
awk中的程式不同于其他語言中的程式,因為awk程式是數(shù)據(jù)驅(qū)動的;也就是說你描述要處理什么樣的數(shù)據(jù)和找到后對它們做什么。大多數(shù)其它語言是過程的;你需要描述,非常詳細地,程式要做的每一步。當(dāng)利用過程語言工作的時候,一般情況下你要清楚地描述要處理的數(shù)據(jù)時很困難的。基于此,awk程式都非常容易閱讀和書寫。
運行awk時,你要指定一個awk程式來告知awk去做什么。這種程式由一些列規(guī)則(rules)組成。(它也可能包含功能定義,一種高級的特性)。每個規(guī)則指定一個要尋找的pattern和找到后執(zhí)行的動作。
句法上,規(guī)則包含一個pattern和其后的動作描述。動作描述由大括號包圍用以與pattern分開。新行分開各個規(guī)則。因此,awk程式看起來是這樣的:
pattern { action }
pattern { action }
1.1如何運行awk程式
有很多途徑運行awk程式。假如程式短的話,在命令行中用awk命令運行它是最簡單的,像下邊這樣:
awk 'program' input-file1 input-file2 ...
當(dāng)程式長的時候,一般方便的做法是將程式放在一個文件中,然后用如下的命令運行:
awk -f program-file input-file1 input-file2 ...
本部分討論這兩種情況,和各個變種形式。
1.1.1單步簡單awk程式
一旦你熟悉awk,你會在想用的時候經(jīng)常輸入簡單的程式。那么,你可以書寫程式讓它作為awk命令的第一個參數(shù),運行它:
awk 'program' input-file1 input-file2 ...
其中,program由一系列的模式(pattern)和執(zhí)行動作(action)組成。
這個命令格式指示shell或者命令解釋器,運行awk并且利用program去處理文件中的記錄(行)。用單引號將program括起,避免使shell將awk的字符解釋成特殊的shell字符。單引號同樣使shell將整個program看成是awk的一個參數(shù),且允許program可以超過一行長。
這種格式對通過shell腳本運行短的或者中長型的awk程式也有用,因為它避免了awk程式對分離的文件的需求。獨立的shell腳本有很好的可依賴性,因為沒有文件錯放的問題。1.1.2 運行沒有輸入文件的awk程式
也可以運行沒有任何輸入文件的awk命令。如果輸入如下命令:
awk 'program'
awk 應(yīng)用program于標(biāo)準(zhǔn)輸入,通常意味著任何你通過終端輸入的東西。這持續(xù)到你用輸入ctrl-d來指示輸入結(jié)束。(在其它操作系統(tǒng)中,可能不一樣,ctrl-z)。
來看一個例子,下邊的程式打印一個友好的提示,來使你不用擔(dān)心計算機編程的復(fù)雜性:
awk "BEGIN { print \" Don't Panic!\" } "
->Don"t Panic!
這個程式?jīng)]有讀取任何輸入。雙引號前的字符'\'是必須的,因為shell的引號規(guī)則—尤其是因為它混合了單引號和雙引號。
下邊的例子模仿cat的功能;它復(fù)制任何你用鍵盤輸入的字符到標(biāo)準(zhǔn)輸出。
Awk '{print}'
1.1.3 運行長程式
有時候你的awk程式可能很長。這種情況下,將程式放在單獨的文件中是很方便的。為了告知awk使用這個文件最為它的program,可以輸入:
awk -f source-file input-file1 input-file2 ...
-f 指示awk程序從source-file中獲取program。例如,我們可以把
BEGIN { print "Don't Panic!" }
放入文件advice中,然后命令:
awk -f advice
做了前述相同的事情。
注意到在advice中,awk程式米有單引號包括。引號只用于在awk命令行中運行的程式。
1.1.4 可執(zhí)行的awk程式
一旦你學(xué)習(xí)了awk,你可能希望寫?yīng)毩⒌腶wk腳本,利用'#!'腳本機制。你可以在很多UNIX系統(tǒng)和GNU系統(tǒng)上這樣做。例如,可以如下更行文件advice:
#! /bin/awk -f
BEGIN { print "Don't Panic!" }
獨立的awk腳本在你寫一個別人可以調(diào)用的程式而別人不知道它使用awk語言的時候是有用的。
1.1.5 awk程式中的注釋
awk語言中,注釋開始于'#',持續(xù)到行尾。'#'沒必要是該行的第一個字符,awk語言忽略行中'#'以后的字符。
1.1.6 shell引號問題
awk "BEGIN {print \" ' \"}" #-》' 打印'
awk 'BEGIN {print "\\"}' #-》\ 打印 \
1.2 實例用到的數(shù)據(jù)文件
本文檔中很多實例用到兩個輸入文件。第一個,BBS-list,代表一列電子公告牌系統(tǒng)及其信息。第二個,inventory-shipped,包含了月度船運信息。兩個文件中,每一行被認(rèn)為是一個記錄。
文件 BBS-list中,每一條記錄包括公告牌名字,電話號碼,牌子波特率和運轉(zhuǎn)時間。最后一列'A'標(biāo)示24小時操作,'B'標(biāo)示只能在晚上和周末,'C'標(biāo)示只能在周末操作。
aardvark 555-5553 1200/300 B
alpo-net 555-3412 2400/1200/300 A
barfly 555-7685 1200/300 A
bites 555-1675 2400/1200/300 A
camelot 555-0542 300 C
core 555-2912 1200/300 C
fooey 555-1234 2400/1200/300 B
foot 555-6699 1200/300 B
macfoo 555-6480 1200/300 A
sdace 555-3430 2400/1200/300 A
sabafoo 555-2127 1200/300 C
數(shù)據(jù)文件 inventory-shipped代表一年中的船運信息。每一記錄包含字段月份,綠色箱子數(shù)目,紅色箱子數(shù)目,橘黃色袋子數(shù)目,藍色包數(shù)目。總共有16項紀(jì)錄,包括去年的12個月份和今年的4個月。
Jan 13 25 15 115
Feb 15 32 24 226
Mar 15 24 34 228
Apr 31 52 63 420
May 16 34 29 208
Jun 31 42 75 492
Jul 24 34 67 436
Aug 15 34 47 316
Sep 13 55 37 277
Oct 29 54 68 525
Nov 20 87 82 577
Dec 17 35 61 401
Jan 21 36 64 620
Feb 26 58 80 652
Mar 24 75 70 495
Apr 21 70 74 514
1.3 一些簡單的例子
接下來的命令運行一個簡單的awk程式,它從輸入文件BBS-list中尋找字符串'foo':
awk ' /foo/ { print $0 } ' BBS-list
當(dāng)包含有'foo'的行被發(fā)現(xiàn),它們將被打印出來,因為'print $0'表示打印當(dāng)前行。(只是單獨的'print'表示同樣的行為,所以我們也可以這樣代替。)
你可能已經(jīng)注意到了斜線號'/'包圍著'foo',斜線號指示'foo'是要尋找的模式(pattern)。這種模式被稱為正則表達式。模式被允許匹配與一個字的一部分。用單引號括起awk的program可以禁止shell將它的任何部分解釋成shell字符。
在awk的規(guī)則中,模式(pattern)或者動作描述可以被省略,但是不能同時。如果模式被省略,動作行為將作用于每一個輸入行。如果動作描述被省略,默認(rèn)的動作是打印匹配模式的每一行。
因此,我們在上一個例子中可以省去動作描述(打印語句和花括號),結(jié)果是一樣的:所有匹配行將被打印出來。對比一下,省去打印語句但是保留花括號會產(chǎn)生一個空動作,標(biāo)示什么都不做(也就是說,沒有行被打。。
很多使用的awk程式只有一兩行。下邊的是一些有用的,但是短小的程式的一個集合。大多是例子用到一個數(shù)據(jù)文件叫data。這只是個占位符。
打印出最長輸入行的長度:
awk ' { if (length($0) > max) max = length($0) }
END { print max } ' data
打印出長度大于80個字符的行:
awk ' length($0) > 80 ' data
打印出data中最長行的長度:
expand data | awk ' { if (x
END { print "maximum line length is " x } '
打印出至少含有一個字段你的行:
awk ' NF > 0' data
打印出0到100之間的7個隨機數(shù):
awk ' BEGIN { for (i=1; i
print int(101 * rand()) }'
打印出files使用的總的字節(jié)數(shù):
ls -l files | awk ' { x+= $5 }
END { print " total bytes: " x } '
打印一個對所有用戶登錄名字的一個排序列表:
awk -F: ' { print $1 } ' /etc/passwd | sort
打印文件的行數(shù):
awk ' END { print NR } ' data
打印文件中的偶數(shù)行:
awk ' NR % 2 == 0 ' data
1.4 雙規(guī)則樣例
awk應(yīng)用每次從輸入文件中讀入一行。對于每一行,awk對每一個規(guī)則的模式進行嘗試。如果有多個模式匹配,相應(yīng)的動作描述將按順序被執(zhí)行。
1.5 一個更復(fù)雜的例子
既然我們已經(jīng)熟練了簡單的任務(wù),讓我們看看典型的awk程式做些什么。這個例子展示了awk怎樣被用于匯總,選擇,重新排列其他應(yīng)用的輸出內(nèi)容:
ls -l | awk ' $6 == "Nov" { sum += $5 }
END { print sum }'
這條命令打印出當(dāng)前文件夾中被最后修改于11月份的問價你的總共字節(jié)數(shù)。
1.6 awk 語句對比行
通常,awk程式中的每一行是一個單獨的語句或者單獨的規(guī)則,如下:
awk ' /12/ { print $0 }
/21/ { print $0 } BBS-list inventory-shipped
然而,gawk忽略任何下邊的符號和關(guān)鍵字后邊的新行:
, { ? : || && do else
新行(\n?)在任何地方被認(rèn)為是語句的結(jié)束。
如果你想將一個語句分開兩行書寫,而新行符終結(jié)一個語句,你可以繼續(xù)語句通過用反斜線'\'結(jié)束第一行。反斜線一定要作為行的最后一個字符。如例子:
awk ' /This regular expression is too long,so continue it\
on the next line/ { print $1 } '
2 正則表達式
正則表達式(regexp)是描述一組字符串的一個途徑。
一個正則表達式被斜線符號'/'括起,它是awk模式,去匹配文本包含這個集合的所有輸入行。最簡單的正則表達式是一序列字母,數(shù)字,或者兩者兼?zhèn)。這樣一種正則表達式匹配任何包含這個序列的字符串。因此,正則表達式 'foo' 匹配任何包含有字符序列'foo'的字符串。
也就是,模式'foo'匹配任何輸入記錄,無論在這記錄的任何位置出現(xiàn)字符序列'foo'。其他種類的正則表達式能讓你描述更加復(fù)雜的字符串。
2.1 如何使用正則表達式
一個正則表達式可以被包括與斜線符號中作為模式。然后這個正則表達式會被測試于整個輸入文本的每一記錄。(正常情況下,只需要匹配文本的某些部分)。例如,下邊的例子打印出任何地方包含有'foo' 的記錄的第二個字段:
awk ' /foo/ { print $2 } ' BBS-list
~(波浪號),~和正則表達式也可以被用于匹配表達式。
2.2 轉(zhuǎn)義序列
一些字符不能原義地包含在字符串常量(如foo)或者正則表達式(如/foo/)中。代替之,它們應(yīng)該用轉(zhuǎn)義序列表示,這是一種以反斜線\開始的字符序列。轉(zhuǎn)義序列的一種使用是在字符串中包含雙引號字符。因為平常的雙引號結(jié)束串,所以你一定要用' \" '去表示一個實在的雙引號字符作為串的一部分。例如:
awk 'BEGIN { print "He said \"hi!\" to her." }'
-->He said "hi!" to her.
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u2/70711/showart_2085889.html |
|