初識gawk, gawk Notes(1)


第一次看見awk這三個字母,是在某實習童鞋的QQ狀態里面,贊同事寫的awk如何高效。

昨天在書暢草草看了下IBM官方技術博里的文章,覺得很贊,很激動,但是有點看不太懂,還是自己抱着教科書,老老實實從頭看起吧。

哦,這里說一下,最近看的shell相關的東西,都是跟着《A Pratical Guide to Linux Commands,Editors, and Shell Programming》這本書的。

gawk是awk的GNU版本。

> 使用條件

主要是用gawk來處理結構化的數據。

什么是結構化呢,我的理解,就是一個文件里面的內容,可以按照某種記錄記錄格式,一條記錄一條記錄地讀,同時,每一條記錄中間用一個分隔符分成了若干個部分,而且所有記錄用同一個分隔符,且所有行用分隔符分出來的部分的數目相同。

當然,gawk可以結構化數據,也可以輸出結構化數據。

另外,要提的一點是,gawk在處理數據的時候,不修改原有的數據文件,只是將數據讀出來,做處理。

> 語法

gawk [option] [program] [file-list]

gawk [options] –f program-file [file-list]

白話說來,運行gawk有兩種方式:

1、直接在shell里面運行。option是運行的選項;program是gawk的代碼,要用' ' 括起來,目的是屏蔽shell對里面內容的解析;file-list是用到的數據文件。[option 有哪些?file-list多個文件怎么處理?]

2、將gawk作為獨立的文件,調用gawk文件來執行。要用-f來標記是使用的gawk文件,同時program-list是gawk文件的列表。

> 選項(option)

僅列出要緊的幾個

-F fs 將fs作為輸入字段分隔符
-f program-file 從program-file 命名文件而不是標准輸入讀取gawk程序,用戶可以多次指定這個選項
-v var=value 將value賦值給var。賦值動作在gawk程序執行之前進行,並用於BEGIN模式。可以在命令行上多次指定這一選項。

> 組成單元

好吧,這是我根據自己理解用的一個名詞。為什么這么說呢?想想以前的各種語言,C,基本組成單元是函數,除了頭文件之外,程序是有各個函數構成的;C++類似;Java,各種方法,所以說,他們的組成單元是 函數 或 方法。

但是gawk呢?如下:

pattern{ action }

每個action用 "{","}"包圍起來,同時,"{"要跟在pattern的同一行

pattern有多種,action各式各樣,但是整個gawk的程序,可以按照這樣的組成單元,分解開來。

所以說,寫gawk程序,就是在源文件里面,構建一個個這樣的組成單元。

gawk的組成單元,有兩個部分,pattern,action。pattern作為一個模式,決定了action在什么情況下運行,而action,則是當記錄符合條件(pattern)時,執行什么樣的動作。這里想用一個圖來說明下:

image

圖1 gawk處理結構化數據示意圖

如圖1所示,gawk的程度,就像是在結構數據上的套子,順着結構數據,從頭讀到尾,然后根據數據是否滿足要求,來決定執行action。這里有一個問題,在gawk文件內,多個組成單元,是怎么樣的一個執行順序,在后面會用實例檢驗一下。

根據pattern的不同,可以講組成單元分成3類:

1、系統默認

有兩個BEGIN,END。

BEGIN在所有代碼開始前執行,也就是說,他不參與pattern的判定。主要是用來初始化一些系統變量等。

END在前面的所有代碼執行完畢后執行,也沒有pattern的判定。主要是清理一些中間生成的臨時數據等等。

2、無pattern

也就是pattern為空,表示所有的結構化數據,每行數據,都要執行這個pattern下的action

3、定義pattern

實際上“定義pattern”和“無pattern”一樣,action都是用戶來寫的,這里之所以區分開,如前面所說,是基於pattern來分的。

這一類,pattern可以是一個條件判斷,也可以是一個正則表達式匹配。

> 系統變量

這些變量被gawk占用了,用的時候,直接拿來就是對應的含義:

表1 變量

$0 當前記錄(作為單個變量)
$1-$n 當前記錄中的字段
FILENAME 當前輸入文件名
FS (Field Split)輸入字段字段分隔符
NF (Number of Fields)當前記錄的字段數目
NR (Number of current Record)當前記錄的記錄編號
OFS (Output Field Split)輸出字段分隔符(默認為空格)
ORS (Output Record Split)輸出記錄分隔符(默認為換行符)
RS (Record Split)輸入記錄分隔符(默認為換行)

FS,RS,可以在BEGIN中,根據具體輸入文件的不同,進行設置。

OFS,ORS,也可以再BEGIN中,根據輸出文件的要求,進行設置。

在程序中,可以通過NF,知道一條記錄中有多少個字段,也就決定了$1-$n的n是多少。

任何時刻都可以修改分隔符的值,具體方法是通過在程序中或者在命令行中使用--assign(-v)選項,將一項新的值指派給對應的變量。

(也就意味着,在輸入和輸出文件中,都可以出現分隔符不同一的情況)

> 函數

gawk的內置函數,用來操作數字和字符串

表2 函數

length(str) 返回字符串str的字符個數,如果沒有參數str,返回當前記錄的字符個數
int(num) 返回num的整數部分
index(str1,str2) 返回str2在str1中的位置,如果str2不存在返回0
split(str,arr,del) 用del做分隔符,將str的元素放置到arr[1]到arr[n]中,返回數組元素個數
sprintf(fmt,args) 根據fmt格式化args並返回格式化后的字符串
substr(str,pos,len) 返回str中從pos開始長度為len個字符的字符串
tolower(str) str字母全部轉為小寫
toupper(str) str字母全部轉為大寫

> 注釋

該行以 # 開頭。

> 關聯數組

我理解它類似於C#的Dictionary<k,v>,可以用字符串做索引:array[string]=value

在使用的時候,利用for可以實現:for (elem in array) print array[elem]

> 控制結構

if-else,while,for 與C語言的對應項基本一致,完全不同於Shell下的對應項,不再贅述。

 

初始gawk,就到這里,用一個例子來結束:

數據文件cars記錄了一組關於汽車的銷售信息(品牌,型號,生產年代,千里里程數,價格),用gawk,寫程序,統計下平均使用年限,所有車的平均價格和新車(晚於2000年)的平均價格

image

圖2 數據文件cars

image

圖3 gawk代碼

image

圖4 運行結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM