一. gawk 基礎(chǔ)
gawk 程序腳本用一對(duì)花括號(hào)來定義,必須將命令放到兩個(gè)花括號(hào)中饲齐。由于 gawk 命令行假定腳本是單個(gè)文本字符串布蔗,所以還必須將腳本放到單引號(hào)中。
gawk 允許將多條命令組合成一個(gè)正常的程序粥脚。要在命令行上的程序腳本中使用多條命令,只要在命令之間加分號(hào)即可包个。
gawk 具有如下功能:
定義變量來保存數(shù)據(jù)
使用算術(shù)和字符串操作符來處理數(shù)據(jù)
使用結(jié)構(gòu)化編程概念來為數(shù)據(jù)處理增加處理邏輯
通過提取數(shù)據(jù)文件中的數(shù)據(jù)元素刷允,將其重新排列或格式化,生成格式化報(bào)告
(一). 命令格式
gawk options program file
選項(xiàng) | 描述 |
---|---|
-F fs | 指定行中劃分?jǐn)?shù)據(jù)字段的字段分隔符 |
-f file | 從指定的文件中讀取程序 |
-v var=value | 定義gawk程序中的一個(gè)變量及其默認(rèn)值 |
-mf N | 指定要處理的數(shù)據(jù)文件中的最大字段數(shù) |
-mr N | 指定數(shù)據(jù)文件中的最大數(shù)據(jù)行數(shù) |
-W keyword | 指定 gawk 的兼容模式或警告等級(jí) |
(二). BEGIN 關(guān)鍵字
gawk 允許指定程序腳本何時(shí)運(yùn)行。gawk 默認(rèn)會(huì)從輸入中讀取一行文本树灶,然后針對(duì)該行的數(shù)據(jù)執(zhí)行程序腳本搀菩。有時(shí)可能需要在處理數(shù)據(jù)前運(yùn)行腳本,比如為報(bào)告創(chuàng)建標(biāo)題破托。BEGIN 關(guān)鍵字會(huì)強(qiáng)制 gawk 在讀取數(shù)據(jù)前執(zhí)行 BEGIN 關(guān)鍵字后指定的程序腳本。
$ cat data.txt
Line 1
Line 2
Line 3
$ gawk 'BEGIN {print "The data3 File Contents:"} {print $0}' data.txt
The data3 File Contents:
Line 1
Line 2
Line 3
(三). END 關(guān)鍵字
與 BEGIN 關(guān)鍵字類似歧蒋,END 關(guān)鍵字允許指定一個(gè)程序腳本土砂,gawk 會(huì)在讀完數(shù)據(jù)后執(zhí)行它。
$ gawk '{print $0} END {print "End of file"}' data.txt
Line 1
Line 2
Line 3
End of file
二. 使用變量
gawk 支持兩種不同類型的變量:內(nèi)建變量谜洽、自定義變量萝映。內(nèi)建變量存放用來處理數(shù)據(jù)文件中的數(shù)據(jù)字段和記錄的信息。
(一). 內(nèi)建變量
1. 字段變量
字段變量允許使用美元符號(hào) $ 和字段在該記錄中的位置來引用記錄對(duì)應(yīng)的字段阐虚。因此使用 $0 代表整行文本序臂,使用 $1 引用記錄中的第一個(gè)數(shù)據(jù)字段,使用 $2 引用第二個(gè)字段实束,依次類推奥秆。
2. 分隔符變量
字段變量是由字段分隔符來劃定的。
變量 | 描述 |
---|---|
FIELDWIDTHS | 由空格分隔的一列數(shù)字咸灿,定義了每個(gè)數(shù)據(jù)字段確切寬度 |
FS | 輸入字段分隔符 (默認(rèn)為空白字符) |
RS | 輸入記錄分隔符 (默認(rèn)為換行符) |
OFS | 輸出字段分隔符 (默認(rèn)為空格) |
ORS | 輸出記錄分隔符 (默認(rèn)為換行符) |
FIELDWIDTHS 變量允許我們不依靠字段分隔符來讀取記錄构订。在一些應(yīng)用中,數(shù)據(jù)并沒有使用字段分隔符避矢,而是被放置在了記錄中的特定列悼瘾。這種情況下,必須設(shè)定 FIELDWIDTHS 變量來匹配數(shù)據(jù)在記錄中的位置审胸。
一旦設(shè)置了 FIELDWIDTH 變量亥宿, gawk 就會(huì)忽略 FS 變量,并根據(jù)提供的字段寬度來計(jì)算字段砂沛。一旦設(shè)定了 FIELDWIDTHS 變量的值烫扼,就不能再改變了。
$ cat data.txt
1005.3247596.37
115-2.349194.00
05810.1298100.1
$ gawk 'BEGIN{FIELDWIDTHS="3 5 2 5"} {print $1,$2,$3,$4}' data.txt
100 5.324 75 96.37
115 -2.34 91 94.00
058 10.12 98 100.1
3. 數(shù)據(jù)變量
變量 | 描述 |
---|---|
ARGC | 當(dāng)前命令行參數(shù)個(gè)數(shù) |
ARGIND | 當(dāng)前文件在 ARGV 中的位置 |
ARGV | 包含命令行參數(shù)的數(shù)組 |
CONVFMT | 數(shù)字的轉(zhuǎn)換格式尺上,默認(rèn)值為%.6 g |
ENVIRON | 當(dāng)前 shell 環(huán)境變量及其值組成的關(guān)聯(lián)數(shù)組 |
ERRNO | 當(dāng)讀取或關(guān)閉輸入文件發(fā)生錯(cuò)誤時(shí)的系統(tǒng)錯(cuò)誤號(hào) |
FILENAME | 用作 gawk 輸入數(shù)據(jù)的數(shù)據(jù)文件的文件名 |
FNR | 當(dāng)前數(shù)據(jù)文件中的數(shù)據(jù)行數(shù) |
IGNORECASE | 設(shè)成非零值時(shí)材蛛,忽略 gawk 命令中出現(xiàn)的字符串的字符大小寫 |
NF | 數(shù)據(jù)文件中的字段總數(shù) |
NR | 已處理的輸入記錄數(shù) |
OFMT | 數(shù)字的輸出格式,默認(rèn)值為 %.6 g |
RLENGTH | 由 match 函數(shù)所匹配的子字符串的長(zhǎng)度 |
RSTART | 由 match 函數(shù)所匹配的子字符串的起始位置 |
ARGC 和 ARGV 變量允許從 shell 中獲得命令行參數(shù)的總數(shù)以及它們的值怎抛。但這可能有點(diǎn)麻煩卑吭,因?yàn)?gawk 并不會(huì)將程序腳本當(dāng)成命令行參數(shù)的一部分。
$ gawk 'BEGIN {print ARGC,ARGV[0],ARGV[1]}' data.txt
2 gawk data.txt
ENVIRON 變量使用關(guān)聯(lián)數(shù)組來提取 shell 環(huán)境變量马绝。數(shù)組索引中的文本是環(huán)境變量名豆赏,而數(shù)組的值則是對(duì)應(yīng)環(huán)境變量的值。
$ gawk 'BEGIN {print ENVIRON["HOME"]; print ENVIRON["PATH"]}'
/root
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
如果只使用一個(gè)數(shù)據(jù)文件作為輸入,F(xiàn)NR 和 NR 的值是相同的掷邦;如果使用多個(gè)數(shù)據(jù)文件作為輸入白胀,F(xiàn)NR 的值會(huì)在處理每個(gè)數(shù)據(jù)文件時(shí)被重置,而 NR 的值則會(huì)繼續(xù)計(jì)數(shù)直到處理完所有的數(shù)據(jù)文件抚岗。
$ cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
$ gawk 'BEGIN{FS=","}{print $1,"NFR="FNR,"NR="NR}' data.txt data.txt
data11 NFR=1 NR=1
data21 NFR=2 NR=2
data31 NFR=3 NR=3
data11 NFR=1 NR=4
data21 NFR=2 NR=5
data31 NFR=3 NR=6
(二). 自定義變量
gawk 自定義變量名可以是任意數(shù)目的字母或杠、數(shù)字和下劃線,但不能以數(shù)字開頭宣蔚。變量名區(qū)分大小寫向抢。
1. 在腳本中給變量賦值
$ gawk 'BEGIN {test="this is a test"; print test}'
this is a test
$ gawk 'BEGIN {x=4; x=x*2+3; print x}'
11
2. 在命令行給變量賦值
$ cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
$ cat script
BEGIN {FS=","}
{print $n}
$ gawk -f script n=2 data.txt
data12
data22
data32
使用命令行參數(shù)來定義變量的值會(huì)有一個(gè)問題,這個(gè)值在代碼的 BEGIN 部分不可用胚委⌒可以用 -v 命令行參數(shù)來解決這個(gè)問題。它允許在 BEGIN 代碼之前設(shè)定變量亩冬。在命令行上艘希,-v 命令行參數(shù)必須放在腳本代碼之前。
$ cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
$ cat script
BEGIN {FS=",";print "The value is", n}
{print $n}
$ gawk -f script n=2 data.txt
The value is
data12
data22
data32
$ gawk -v n=2 -f script data.txt
The value is 2
data12
data22
data32
三. 處理數(shù)組
在 gawk 中使用關(guān)聯(lián)數(shù)組提供數(shù)組的功能硅急。關(guān)聯(lián)數(shù)組不需要使用連續(xù)的數(shù)字來標(biāo)識(shí)數(shù)組中的數(shù)據(jù)元素覆享,而是用各種字符串來引用值。每個(gè)索引字符串都必須能夠唯一地標(biāo)識(shí)出賦給它的數(shù)據(jù)元素铜秆。
(一). 定義數(shù)組
數(shù)組變量賦值的格式為:var[index] = element淹真。其中 var 是變量名,index 是關(guān)聯(lián)數(shù)組的索引值连茧,element 是數(shù)據(jù)元素值核蘸。
$ gawk 'BEGIN {
num[1]=2
num[2]=3
str["name"]="ziqing"
total=num[1]+num[2]
print str["name"],total
}'
ziqing 5
(二). 遍歷數(shù)組
如果要在 gawk 中遍歷一個(gè)關(guān)聯(lián)數(shù)組,可以用特殊的 for 語句啸驯。for 語句在每次循環(huán)時(shí)將關(guān)聯(lián)數(shù)組 array 的下一個(gè)索引值賦給變量 var客扎,然后執(zhí)行一遍 statements。這個(gè)變量中存儲(chǔ)的是索引值而不是數(shù)組元素值罚斗。索引值不會(huì)按任何特定順序返回徙鱼。
for (var in array)
{
statements
}
$ gawk 'BEGIN {
arr["a"]=1
arr["b"]=2
arr["c"]=3
arr["d"]=4
for (var in arr)
{
print "key:",var," value:",arr[var]
}
}'
key: a value: 1
key: b value: 2
key: c value: 3
key: d value: 4
(三). 刪除數(shù)組變量
從關(guān)聯(lián)數(shù)組中刪除數(shù)組索引要用一個(gè)特殊的命令:delete array[index]。刪除命令會(huì)從數(shù)組中刪除關(guān)聯(lián)索引值和相關(guān)的數(shù)據(jù)元素值针姿。
$ gawk 'BEGIN {
arr["a"]=1
arr["b"]=2
arr["c"]=3
arr["d"]=4
for (var in arr)
{
print "key:",var," value:",arr[var]
}
print "============="
delete arr["b"]
for (var in arr)
{
print "key:",var," value:",arr[var]
}
}'
key: a value: 1
key: b value: 2
key: c value: 3
key: d value: 4
=============
key: a value: 1
key: c value: 3
key: d value: 4
四. 使用模式
(一). 正則表達(dá)式
$ cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
$ gawk 'BEGIN{FS=","} /11/{print $1,$2}' data.txt
data11 data12
(二). 匹配操作符
匹配操作符 (~) 允許將正則表達(dá)式限定在記錄中的特定數(shù)據(jù)字段袱吆。可以指定匹配操作符距淫、數(shù)據(jù)字段變量以及要匹配的正則表達(dá)式绞绒。也可以用 ! 符號(hào)來排除正則表達(dá)式的匹配。
$ cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
$ gawk 'BEGIN{FS=","} $1 ~ /^data2/{print $1,$2}' data.txt
data21 data22
$ gawk 'BEGIN{FS=","} $1 !~ /^data2/{print $1,$2}' data.txt
data11 data12
data31 data32
(三). 數(shù)學(xué)表達(dá)式
可以在匹配模式中使用數(shù)學(xué)表達(dá)式榕暇。這在匹配數(shù)據(jù)字段中的數(shù)字值時(shí)非常方便蓬衡。也可以對(duì)文本數(shù)據(jù)使用表達(dá)式喻杈,數(shù)據(jù)必須跟模式嚴(yán)格匹配。
$ gawk -F: '$4 == 0{print $1}' /etc/passwd
root
sync
shutdown
halt
operator
五. 結(jié)構(gòu)化命令
(一). if 語句
if (condition) statement1
if (condition) statement1; else statement2
$ cat data.txt
10
5
13
50
34
$ gawk '{if($1 > 20) print $1}' data.txt
50
34
$ cat data.txt
10
5
13
50
34
$ gawk '{if($1 > 20) print $1; else print $1 *2}' data.txt
20
10
26
50
34
(二). while 語句
gawk 支持在 while 循環(huán)中使用 break 語句和 continue 語句狰晚,允許從循環(huán)中跳出筒饰。
while (condition)
{
statements
}
$ cat data.txt
130 120 135
160 113 140
145 170 215
$ gawk '{i=1;total=0;while(i<4){total=total+$i;i++;};print "total: "total}' data.txt
total: 385
total: 413
total: 530
(三). do-while 語句
do
{
statements
} while (condition)
$ cat data.txt
130 120 135
160 113 140
145 170 215
$ gawk '{
i=1;total=0
do{total=total+$i;i++;}while(total<150)
print "total:"total
}' data.txt
total:250
total:160
total:315
(四). for 語句
for( variable assignment; condition; iteration process)
$ gawk 'BEGIN{total=0;for(i=1;i<=10;i++)(total=total+i);print "total: "total}'
total: 55
六. 格式化打印
gawk 中的 printf 命令允許指定具體如何顯示數(shù)據(jù)的指令。
printf "format string", var1, var2 . . .
format string 是格式化輸出的關(guān)鍵壁晒。它會(huì)用文本元素和格式化指定符來具體指定如何呈現(xiàn)格式化輸出瓷们。格式化指定符會(huì)指明顯示什么類型的變量以及如何顯示。gawk 會(huì)將每個(gè)格式化指定符作為占位符秒咐,供命令中的變量使用换棚。第一個(gè)格式化指定符對(duì)應(yīng)列出的第一個(gè)變量,第二個(gè)對(duì)應(yīng)第二個(gè)變量反镇,依此類推。
格式化指定符格式:%[modifier]control-letter娘汞。其中 control-letter 是一個(gè)單字符代碼歹茶,用于指明顯示什么類型的數(shù)據(jù),而 modifier 則定義了可選的格式化特性你弦。
控制字母 | 描述 |
---|---|
c | 將一個(gè)數(shù)作為 ASCII 字符顯示 |
d | 顯示一個(gè)整數(shù)值 |
i | 顯示一個(gè)整數(shù)值(跟 d 一樣) |
e | 用科學(xué)計(jì)數(shù)法顯示一個(gè)數(shù) |
f | 顯示一個(gè)浮點(diǎn)值 |
g | 用科學(xué)計(jì)數(shù)法或浮點(diǎn)數(shù)顯示(選擇較短的格式) |
o | 顯示一個(gè)八進(jìn)制值 |
s | 顯示一個(gè)文本字符串 |
x | 顯示一個(gè)十六進(jìn)制值 |
X | 顯示一個(gè)十六進(jìn)制值惊豺,但用大寫字母 A~F |
除了控制字母外,還有 3 種修飾符可以用來進(jìn)一步控制輸出:
width禽作,指定輸出字段最小寬度的數(shù)字值尸昧。如果輸出短于這個(gè)值,printf 會(huì)將文本右對(duì)齊旷偿,并用空格進(jìn)行填充烹俗。如果輸出比指定的寬度還要長(zhǎng),則按照實(shí)際的長(zhǎng)度輸出
prec萍程,指定浮點(diǎn)數(shù)中小數(shù)點(diǎn)后面位數(shù)幢妄,或者文本字符串中顯示的最大字符數(shù)
-,指明在向格式化空間中放入數(shù)據(jù)時(shí)采用左對(duì)齊而不是右對(duì)齊
七. 內(nèi)建函數(shù)
一. 數(shù)學(xué)函數(shù)
函數(shù) | 描述 |
---|---|
atan2(x, y) | x/y 的反正切茫负, x 和y 以弧度為單位 |
cos(x) | x 的余弦蕉鸳, x 以弧度為單位 |
exp(x) | x 的指數(shù)函數(shù) |
int(x) | x 的整數(shù)部分,取靠近零一側(cè)的值 |
log(x) | x 的自然對(duì)數(shù) |
rand( ) | 比 0 大比 1 小的隨機(jī)浮點(diǎn)值 |
sin(x) | x 的正弦忍法, x 以弧度為單位 |
sqrt(x) | x 的平方根 |
srand(x) | 為計(jì)算隨機(jī)數(shù)指定一個(gè)種子值 |
int() 會(huì)生成一個(gè)值的整數(shù)部分潮尝,但并不會(huì)四舍五入取近似值。它會(huì)生成該值和 0 之間最接近該值的整數(shù)饿序。
函數(shù) | 描述 |
---|---|
and(v1, v2) | 執(zhí)行值 v1 和 v2 的按位與運(yùn)算 |
compl(val) | 執(zhí)行 val 的補(bǔ)運(yùn)算 |
lshift(val, count) | 將值 val 左移 count 位 |
or(v1, v2) | 執(zhí)行值 v1 和 v2 的按位或運(yùn)算 |
rshift(val, count) | 將值val右移 count 位 |
xor(v1, v2) | 執(zhí)行值 v1 和 v2 的按位異或運(yùn)算 |
二. 字符串函數(shù)
asort(s [,d])
將數(shù)組 s 按數(shù)據(jù)元素值排序勉失。索引值會(huì)被替換成表示新的排序順序的連續(xù)數(shù)字。如果指定了d嗤堰,則排序后的數(shù)組會(huì)存儲(chǔ)在數(shù)組 d 中戴质。
asorti(s [,d])
將數(shù)組 s 按索引值排序度宦。生成的數(shù)組會(huì)將索引值作為數(shù)據(jù)元素值,用連續(xù)數(shù)字索引來表明排序順序告匠。另外如果指定了 d戈抄,排序后的數(shù)組會(huì)存儲(chǔ)在數(shù)組 d 中。
gensub(r, s, h [, t])
查找變量 $0 或目標(biāo)字符串 t 來匹配正則表達(dá)式 r后专。如果 h 是一個(gè)以 g 或 G 開頭的字符串划鸽,就用 s 替換掉匹配的文本。如果 h 是一個(gè)數(shù)字戚哎,它表示要替換掉第 h 處 r 匹配的地方裸诽。
gsub(r, s [,t])
查找變量 $0 或目標(biāo)字符串 t來匹配正則表達(dá)式 r。如果找到了型凳,就全部替換成字符串 s丈冬。
index(s, t)
返回字符串t在字符串 s 中的索引值,如果沒找到的話返回 0
length([s])
返回字符串 s 的長(zhǎng)度甘畅;如果沒有指定的話埂蕊,返回 $0 的長(zhǎng)度。
match(s, r [,a])
返回字符串 s 中正則表達(dá)式 r 出現(xiàn)位置的索引疏唾。如果指定了數(shù)組 a蓄氧,它會(huì)存儲(chǔ) s 中匹配正則表達(dá)式的那部分。
split(s, a [,r])
將 s 用 FS 字符或正則表達(dá)式 r 分開放到數(shù)組 a 中槐脏。返回字段的總數(shù)喉童。
sprintf(format,variables)
用提供的 format 和 variables 返回一個(gè)類似于 printf 輸出的字符串。
sub(r, s [,t])
在變量 $0 或目標(biāo)字符串t中查找正則表達(dá)式r的匹配顿天。如果找到了堂氯,就用字符串 s 替換掉第一處匹配。
substr(s, i [,n])
返回 s 中從索引值 i 開始的 n 個(gè)字符組成的子字符串牌废。如果未提供 n祖灰,則返回 s 剩下的部分。
tolower(s)
將 s 中的所有字符轉(zhuǎn)換成小寫畔规。
toupper(s)
將 s 中的所有字符轉(zhuǎn)換成大寫局扶。
三. 時(shí)間函數(shù)
函數(shù) | 描述 |
---|---|
mktime(datespec) | 將一個(gè)按 YYYY MM DD HH MM SS [DST] 格式指定的日期轉(zhuǎn)換成時(shí)間戳值 |
strftime(format[,timestamp]) | 將當(dāng)前時(shí)間的時(shí)間戳或 timestamp 轉(zhuǎn)化格式化日期 |
systime( ) | 返回當(dāng)前時(shí)間的時(shí)間戳 |