《Linux命令行與shell腳本編程大全》 第二十一章 學習筆記

第一部分:Linux命令行
《Linux命令行與shell腳本編程大全》 第一章:初識Linux shell
《Linux命令行與shell腳本編程大全》 第二章:走進shell
《Linux命令行與shell腳本編程大全》 第三章:基本的bash shell命令
《Linux命令行與shell腳本編程大全》 第四章:更多的bash shell命令
《Linux命令行與shell腳本編程大全》 第五章:使用Linux環境變量
《Linux命令行與shell腳本編程大全》 第六章:理解Linux文件權限
《Linux命令行與shell腳本編程大全》 第七章:管理文件系統
《Linux命令行與shell腳本編程大全》 第八章:安裝軟件程序
《Linux命令行與shell腳本編程大全》 第九章:使用編輯器

第二部分:shell腳本編程基礎
《Linux命令行與shell腳本編程大全》 第十章:構建基本腳本
《Linux命令行與shell腳本編程大全》 第十一章:使用結構化命令
《Linux命令行與shell腳本編程大全》 第十二章:更多的結構化命令
《Linux命令行與shell腳本編程大全》 第十三章:處理用戶輸入
《Linux命令行與shell腳本編程大全》 第十四章:呈現數據
《Linux命令行與shell腳本編程大全》 第十五章:控制腳本

第三部分:高級shell編程
《Linux命令行與shell腳本編程大全》 第十六章:創建函數
《Linux命令行與shell腳本編程大全》 第十七章:圖形化桌面上的腳本編程
《Linux命令行與shell腳本編程大全》 第十八章:初識sed和gawk
《Linux命令行與shell腳本編程大全》 第十九章:正則表達式
《Linux命令行與shell腳本編程大全》 第二十章:sed進階
《Linux命令行與shell腳本編程大全》 第二十一章:gawk進階
《Linux命令行與shell腳本編程大全》 第二十二章:使用其他shell

第四部分:高級shell腳本編程主題
《Linux命令行與shell腳本編程大全》 第二十三章:使用數據庫
《Linux命令行與shell腳本編程大全》 第二十四章:使用Web
《Linux命令行與shell腳本編程大全》 第二十五章:使用E-mail
《Linux命令行與shell腳本編程大全》 第二十六章:編寫腳本實用工具
《Linux命令行與shell腳本編程大全》 第二十七章:shell腳本編程進階


第二十一章:gawk進階

 

使用變量

gawk支持兩種類型的變量:

內建變量

自定義變量

內建變量

字段和數據行分割符變量

使用美元符號($)和數據字段在數據行中位置對應的數值來引用該數據行中的字段。

比如,要引用數據行中的第二個字段就使用$2

gawk數據字段和數據行變量

變量描述
FIELDWIDTHS由空格分隔開的定義了每個數據字段確切寬度的一列數字
FS輸入字段分割符
RS輸入數據行分割符
OFS輸入字段分隔符
ORS輸入數據行分隔符

OFS默認值爲空格

$ cat column_data.txt
1987-06-05
$ gawk 'BEGIN{FS="-"} {print $1,$2,$3}' column_data.txt 
1987 06 05
$ gawk 'BEGIN{FS="-";OFS=":"} {print $1,$2,$3}' column_data.txt 
1987:06:05

一旦設置了FIELDWIDTHS,FS就會失效

一旦設置了FIELDWIDTHS值,就不可再更改

下面演示一下RS

假設我們有一份聯繫人名單,每個聯繫人之間用空行分割,格式如下

$ cat contacts 
Name1
Addr1
ZipCode1
Tele1

Name2
Addr2
ZipCode2
Tele2

Name3
Addr3
ZipCode3
Tele3

下面我們想讀取姓名與電話。

默認情況下,gawk以換行符爲行分隔符,這裏我們可以使用空作爲行分隔符。這樣做的結果就是,使得每一個聯繫人作爲單獨的“一行”。然後我們再把字段分隔符設置爲換行符,這樣就可以提取我們所需要的內容了。

$ gawk 'BEGIN{FS="\n";RS=""} {print $1,$4}' contacts 
Name1 Tele1
Name2 Tele2
Name3 Tele3

數據變量

變量描述
ARGC當前命令行參數個數
ARGIND當前文件在ARGV中的位置
ARGV包含命令行參數的數組
CONVFMT數字的轉換格式(參見print語句);默認值爲%.6 g
ENVIRON當前shell環境變量及其值組成的關聯數組
ERRNO當讀取或關閉輸入文件發生錯誤時的系統錯誤號
FILENAME用作gawk輸入數據的數據文件的文件名
FNR當前數據文件中的數據行數
IGNORECASE設成非0值時,忽略gawk命令中出現的字符串的字符大小寫
NF數據文件中的字段總數
NR已處理的輸入數據行數目
OFMT數字的輸出格式;默認值爲%.6 g
RLENGTH由match函數所匹配的子字符串的長度
RSTART由match函數所匹配的子字符串的起始位置

在gawk中引用gawk變量的時候,不需要美元符號

$ gawk 'BEGIN{print ARGC,ARGV[0],ARGV[1]}' contacts
2 gawk contacts

上面命令中共兩個參數,gawk以及contacts

注意:gawk後的腳本不算參數

我們可以通過如下方式獲取系統環境變量,既而在gawk中使用。

$ gawk 'BEGIN{print ENVIRON["HOME"]}' 
/home/su1216

我們可以通過如下方式來指定最後一個字段

$ gawk 'BEGIN{FS=":"; OFS=":"} {print $1,$NF}' /etc/passwd
root:/bin/bash
daemon:/bin/sh
bin:/bin/sh
sys:/bin/sh
......

注意:這裏gawk先把NF計算出來,然後再執行$number,而不是像shell中把$NF視爲對NF變量的引用。

下面看一下FNR與NR的區別

$ gawk 'BEGIN{FS="\n";RS=""} {print $1,"FNR="FNR, "NR="NR}' contacts contacts 
Name1 FNR=1 NR=1
Name2 FNR=2 NR=2
Name3 FNR=3 NR=3
Name1 FNR=1 NR=4
Name2 FNR=2 NR=5
Name3 FNR=3 NR=6

如果只使用一個數據文件作爲輸入,那麼FNR與NR則一致。

處理第二個文件時,FNR變量被重置。

自定義變量

在腳本中給變量賦值

同shell中的變量賦值類似:

$ gawk '
> BEGIN{
> test="This is a test."
> print test
> test="Test again."
> print test
> }'
This is a test.
Test again.

還可以在其中直接進行數學運算

$ gawk '
BEGIN{
x=1                   
print "x="x
x=(x+1)**2
print "x="x
}'
x=1
x=4

可以直接進行求餘(%)和方冪(**或者^)運算

在命令行上給變量賦值

可以在gawk腳本之外給gawk中變量賦值

$ cat gawk_script
BEGIN{FS=":"}{print $n}

上面是一個普通的gawk腳本,其中使用了變量n,但是並沒有爲其進行初始化。

$ gawk -f gawk_script n=1 /etc/passwd
root
daemon
bin
......

但是這個變量在BEGIN中是無效的,如果想在BEGIN中生效,需要使用-v選項。

$ gawk -v n=1 -f gawk_script /etc/passwd

 

處理數組

gawk使用關聯數組來提供數組功能,它的索引可以是任意文本字符串。

定義數組變量

$ gawk '
> BEGIN{test["a"]="a"
> print test["a"]
> }'
a

遍歷數組變量

可以使用for語句:

for (var in array)
{
    statements
}

例如:

$ gawk '
> BEGIN {
> test["a"]="a1"
> test["b"]="b2"
> test["c"]="c3"
> for (var in test)
> {
>     print var,test[var]
> }
> }'
a a1
b b2
c c3

刪除數組變量

delete array[index]

$ gawk '
> BEGIN {
> test["a"]="a1"
> test["b"]="b2"
> test["c"]="c3"
> delete test["b"]
> for (var in test)
> {
>     print var,test[var]
> }
> }'
a a1
c c3

 

使用模式

BEGIN和END是用來在讀取數據流之前或之後執行命令的特殊模式。

正則表達式

正則表達式必須出現在它要控制的程序腳本的左花括號前:

$ gawk '/Name[0-9]/{print $0}' contacts 
Name1
Name2
Name3

匹配操作符(matching operator)

匹配操作符允許將正則表達式限定在數據行中的特定數據字段。匹配操作符是波浪線(~)。需要一起指定匹配操作符、數據字段變量以及正則表達式:

$ gawk 'BEGIN{FS=":"} $1 ~ /sys/{print $0}' /etc/passwd
sys:x:3:3:sys:/dev:/bin/sh
syslog:x:101:103::/home/syslog:/bin/false

這裏$1表示第一個字段,也就是說,打印出第一個字段中含有sys字樣的行

可以使用!~來過濾沒有滿足正則表達式的字符串。

$ gawk 'BEGIN{FS=":"} $1 !~ /[aeiou]/{print $0}' /etc/passwd
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
gdm:x:113:120:Gnome Display Manager:/var/lib/gdm:/bin/false
sshd:x:115:65534::/var/run/sshd:/usr/sbin/nologin

數學表達式

可以使用下面幾種形式:

x == y

x <= y

x < y

x > y

x >= y

這裏不僅侷限於數值比較,也可以作用在字符串上。

$ gawk 'BEGIN{FS=":"} $4 == 0{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
$ gawk 'BEGIN{FS=":"} $1 == "sys"{print $0}' /etc/passwd
sys:x:3:3:sys:/dev:/bin/sh

 

結構化命令

if語句

語句格式:

if(condition)
    statement

if(condition) statement

if(condition){
    statements
}

if(condition){
    statements
}else{
    statements
}

if(condition) statement1; else statement2

while語句

語句格式:

while(condition){
    statements
}

do-while語句

語句格式:

do
{
    statements
} while (condition)

for語句

gawk支持C風格的for循環

語句格式:

for(variable assignment; condition; iteration process)

 

格式化打印

printf命令格式:

printf "format string", var1, var2 ...

gawk程序會將每個格式化指定符作爲命令中列出的每個變量的佔位符使用。第一個格式化指定符會匹配列出的第一個變量,第二個會匹配第二個變量,依此類推。

格式化指定符采用如下格式:

%[modifier]control-letter

其中control-letter指明顯示什麼類型數據值的單字符碼,而modifier定義了另一個可選的格式化特性。

格式化指定符的控制字母

控制字母描述
c將一個數作爲ASCII字符顯示
d顯示一個整數值
i顯示一個整數值(跟d一樣)
e用科學記數法顯示一個數
f顯示一個浮點值
g用科學記數法或浮點數中較短的顯示
o顯示一個八進制值
s顯示一個文本字符串
x顯示一個十六進制值
X顯示一個十六進制值,但用大寫字符A-F

除了控制字母外,還有3種修飾符可以用來進一步控制輸出。

width:指定了輸出字段最小寬度的數字值。如果短於這個值,printf會向右對齊,並用空格來填充這段空間。如果輸出比指定的寬度還要長,它就覆蓋width值。

prec:指定了浮點數中小數點後面位數的數字值,或者文本字符串中顯示的最大字符數。

-(減號):向格式化空間中放入數據時採用左對齊。

printf每打印一次,不會自動換行。

$ cat numbers 
1 2 3
123 456 789
172 245 946

$ gawk '{
> total = 0
> for (i = 1; i < 4; i++)
> {
>     total += $i
> }
> avg = total/3
> printf "Average: %5.1f\n",avg
> }' numbers
Average:   2.0
Average: 456.0
Average: 454.3

上面指定了顯示浮點數,輸出最小寬度是5,保留小數後一位,右對齊。

 

內建函數

gawk數學函數

函數描述
atan2(x,y)x/y的反正切,x和y以弧度爲單位
cos(x)x的餘弦,x以弧度爲單位
exp(x)x的指數函數
int(x)x的整數部分,取靠近0一側的值
log(x)x的自然對數
rand()比0大比1小的隨機浮點值
sin(x)x的正弦,x以弧度爲單位
sqrt(x)x的平方根
srand(x)爲計算隨機數指定一個種子值

除了標準函數外,gawk還支持一些按位操作數據的函數

and(v1, v2):v1和v2的按位與運算

compl(val):val的補運算

lshift(val, count):將值val左移count位

or(v1, v2):v1和v2的按位或運算

rshift(val, count):將值val右移count位

xor(v1, v2):執行值v1和v2的按位異或運算

 

gawk字符串函數

函數描述
asort(s [, d])將數組s按數據元素值排序。索引值會被替換成表示新的排序順序的連續數字。如果指定了d,則排序後的數組回存儲在數組d中
asorti(s [, d])將數組s按索引值排序。生成的數組會將索引值作爲數據元素值,用連續數組索引來表明排序順序。如果指定了d,排序後的數組回存儲在數組d中
gensub(r, s, h [, t])查找變量$0或目標字符串t(如果提供了的話)來匹配正則表達式r。如果h是一個以g或者G開頭的字符串,就用s替換掉匹配的文本。如果h是一個數字,它表示要替換掉第幾處r匹配的地方
gsub(r, s, [, t])查找變量$0或目標字符串t(如果提供了的話)來匹配正則表達式r。如果找到了,就全部替換成字符串s
index(s, t)返回字符串t在字符串s中的索引值,如果沒找到的話,返回0
length([s])返回字符串s的長度,如果沒有指定的話,返回$0的長度
match(s, r [, a])返回字符串s中正則表達式r出現位置的索引。如果指定了數組a,它會存儲s中匹配正則表達式的那部分
split(s, a [, r])將s用FS字符或正則表達式r(如果指定了的話),分開放到數組a中。返回字段的總數
sprintf(format, variables)用提供的format和variables返回一個類似於printf輸出的字符串
sub(r, s [, t])在變量$0或目標字符串t中查找正則表達式r的匹配。如果找到了,就用字符串s替換掉第一處匹配
substr(s, i [, n])返回s中從索引值i開始的n個字符組成的子字符串。如果未提供n,則返回s剩下的部分
tolower(s)將s的所有字符轉換成小寫 
toupper(s)將s的所有字符轉換成大寫 

 

gawk的時間函數

函數描述
mktime(datespec)將一個YYYY MM DD HH MM SS [DST]格式置頂的日期轉換徹骨時間戳(時間戳指:自1970-01-01 00:00:00 UTC到現在,以秒爲單位的計數,通常稱epoch time)
strftime(format [, timestamp])將當前時間的時間戳huotimestamp(如果提供了的話)轉化成用shell函數格式date()的格式化日期
systime()返回當前時間的時間戳(同上面的時間戳)

 

自定義函數

定義函數

必須使用function關鍵字

function name([variables])
{
    statements
}

可以使用return語句返回值

使用自定義函數

定義函數時,必須在所有代碼塊之前,包括BEGIN

$ gawk '
> function test(v1){
>     print v1
> }
> BEGIN{
> test("abc")
> }
> '
abc

使用函數庫

1.首先需要創建一個存儲gawk函數的文件:

$ cat gawk_lib
function test(v1){
    print v1
}

function add(){
    print $1+$2+$3
}

2.然後通過使用-f選項來指定函數庫即可:

$ cat gawk_lib_test
BEGIN{
    FS=" "
}

{
    add()
}


$ gawk -f gawk_lib -f gawk_lib_test numbers 
6
1368
10363

 

 

轉貼請保留以下鏈接

本人blog地址

http://su1216.iteye.com/

http://blog.csdn.net/su1216/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章