Awk是一種通用腳本語言,用于高級文本處理的。它主要用作報告和分析工具。與大多數(shù)其他程序性編程語言不同。
Awk是數(shù)據(jù)驅(qū)動的,這意味著您必須定義一組針對輸入文本要執(zhí)行的操作。它獲取輸入數(shù)據(jù),對其進行轉(zhuǎn)換,然后將結(jié)果發(fā)送到標(biāo)準(zhǔn)輸出。
awk有幾種不同的實現(xiàn)。我們將使用Awk的GNU實現(xiàn),稱為gawk。在大多數(shù)Linux發(fā)行版可用,awk
命令只gawk
的符號鏈接。
在本教程的所有示例中,我們將使用teams.txt文件作為awk的輸入,teams.txt文件內(nèi)容如下所示。
Bucks Milwaukee 60 22 0.732
Raptors Toronto 58 24 0.707
76ers Philadelphia 51 31 0.622
Celtics Boston 49 33 0.598
Pacers Indiana 48 34 0.585
記錄和字段
Awk可以處理文本數(shù)據(jù)和流。將輸入的數(shù)據(jù)分為記錄和字段。Awk一次對一條記錄進行操作,直到達到輸入結(jié)束為止。
記錄由記錄分隔符分隔。默認(rèn)的記錄分隔符是換行符,這意味著文本數(shù)據(jù)中的每一行都是一條記錄。可以使用RS
變量來設(shè)置記錄分的隔符。
記錄由多個字段組成,并且使用字段分隔符分隔。默認(rèn)情況下,字段之間用空格分隔,可以是一個或多個制表符,空格等,你可以使用awk命令的-F
選項指定字段的分隔符。
每條記錄中的字段都可以使用美元符號$
后跟字段編號表示,從1開始。第一個字段由$1
表示,第二個字段由$2
表示。
依此類推,最后一個字段也可以用特殊變量$NF
表示。整個記錄可以用$0
表示。
下面可以直觀展示記錄和字段的關(guān)系,也是awk處理文本數(shù)據(jù)默認(rèn)使用的記錄分隔符,即換行符。字段分隔符是空格符。
tmpfs 788M 1.8M 786M 1% /run/lock
/dev/sda1 234G 191G 31G 87% /
|-------| |--| |--| |--| |-| |--------|
$1 $2 $3 $4 $5 $6 ($NF) --> 字段 $1,$2...字段
|-----------------------------------------|
$0 --> 記錄由多個字段組成的單行記錄
awk命令
要使用awk
處理文本,需要編寫程序來告訴awk命令該做什么。程序由一系列規(guī)則和用戶定義的函數(shù)組成。
每個規(guī)則包含模式pattern和操作action的鍵值對。多個規(guī)則使用換行符或分號;
分隔。通常awk程序看起來就像這樣pattern { action }
。
當(dāng)awk
處理數(shù)據(jù)時,如果模式與記錄匹配,awk將會對記錄執(zhí)行指定的操作。當(dāng)規(guī)則沒有模式時,所有記錄/行都匹配。
awk action必須使用花括號{}
括起來,并由多個語句組成。每個語句指定要執(zhí)行的操作。
action可以有一個或者多個語句,使用用換行符或分號;
隔開。如果規(guī)則中沒有action,則默認(rèn)打印整個記錄。
Awk支持不同類型的語句,包括表達式,條件,輸入,輸出語句等。最常見的awk語句是。
exit
停止執(zhí)行整個程序并退出。next
停止處理當(dāng)前記錄,并移至輸入數(shù)據(jù)下一個記錄。
print
打印記錄,字段,變量和自定義文本。printf
使您可以更好地控制輸出格式,類似于C和bash的printf
函數(shù)。
編寫awk程序時,井號#
之后直至行末的所有內(nèi)容均都被視為注釋。可以使用反斜杠\\
將長行分成多行。
運行awk程序
awk程序可以通過多種方式運行。如果程序簡短且簡單,則可以將其直接通過命令行傳遞給awk解釋器。
在命令行運行awk程序時,應(yīng)將程序括在單引號''
中,這樣可以不會被shell程序解釋。這是在命令運行awk程序的語法形式awk 'program' input-file...
。
'program'
是awk要運行的程序,input-file
是輸入文件,可以是一個或者多個文件。
如果程序又大又復(fù)雜,最好將其放入文件中,并使用-f
選項將文件傳遞給awk
命令。這是運行awk運行程序文件的語法形式awk -f program-file input-file...
。
program-file
是awk程序的文件,input-file
是輸入文件,可以是一個或者多個文件。
awk 'program' input-file...
awk -f program-file input-file...
Awk模式
awk中的模式控制著是否要執(zhí)行相關(guān)聯(lián)的操作。Awk支持不同類型的模式,包括正則表達式,關(guān)系表達式,范圍和特殊表達式模式。
當(dāng)沒有模式時,將匹配每個輸入的記錄。命令awk '{ print $3 }' teams.txt
僅包含操作,沒有模式。
程序?qū)⒋蛴∶織l記錄的第三個字段$3
,默認(rèn)字段分隔符是空格,所以以下數(shù)值是teams.txt文件的第三列的數(shù)據(jù)。
awk '{ print $3 }' teams.txt
60
58
51
49
48
正則表達式模式
正則表達式是與一組字符串匹配的模式。Awk正則表達式模式包含在斜杠//
中。這是正則表達式模式語法形式/regex pattern/ { action }
。
模式可以是任何類型的擴展正則表達式。最基本的示例是文字或字符串匹配。
例如命令awk '/0.5/ { print $1 }' teams.txt
僅打印包含0.5記錄的第一個字段。
命令awk '/^[0-9][0-9]/ { print $1 }' teams.txt
將會搜索以兩個或多個數(shù)字開頭的記錄,并打印第一個字段。
awk '/0.5/ { print $1 }' teams.txt
Celtics
Pacers
awk '/^[0-9][0-9]/ { print $1 }' teams.txt
76ers
關(guān)系表達模式
關(guān)系表達式模式通常用于匹配指定字段或變量的內(nèi)容。默認(rèn)情況下,正則表達式模式與記錄進行匹配。
要將正則表達式與字段進行匹配,請指定字段并針對模式使用包含比較運算符約等于號~
。要匹配不包含指定模式的字段,請使用不約等于運算符!~
。
除了約等于和不約等于符號之外,您可以比較字符串或數(shù)字之間的關(guān)系,例如大于>,小于<,等于=符號。
例如命令awk '$2 ~ /ia/ { print $1 }' teams.txt
將會搜索第二個字段包含ia
的記錄并打印第一個字段。
awk '$2 ~ /ia/ { print $1 }' teams.txt
76ers
Pacers
例如命令awk '$2 !~ /ia/ { print $1 }' teams.txt
將會搜索第二個字段不包含ia
的記錄并打印第一個字段。
awk '$2 !~ /ia/ { print $1 }' teams.txt
Bucks
Raptors
Celtics
例如命令awk '$3 > 50 { print $1 }' teams.txt
將會搜索三字段大于50的所有記錄,并打印第一字段。
awk '$3 > 50 { print $1 }' teams.txt
Bucks
Raptors
76ers
范圍模式
范圍模式由用逗號分隔的兩個模式組成,從匹配第一個模式的記錄開始,直到匹配第二個模式的記錄停止匹配。
也就是說匹配兩個模式之間的記錄都會被執(zhí)行相關(guān)的操作。即使中間記錄沒有匹配模式也將會被執(zhí)行相關(guān)操作。
但有一點值得注意的是范圍模式不能與某些模式表達式組合使用。但范圍模式可以與關(guān)系表達式組合使用。
例如命令awk '/Raptors/,/Celtics/ { print $1 }' teams.txt
將會搜索從包含Raptors的記錄開始到包含Celtics記錄結(jié)束的所有記錄。
然后打印兩個模式之間所有記錄的第一個字段{ print $1 }
。
awk '/Raptors/,/Celtics/ { print $1 }' teams.txt
Raptors
76ers //這個記錄沒有匹配到兩個模式中任意一個,但它在兩個模式之間,所以也會打印
Celtics
例如命令awk '$4 == 31, $4 == 33 { print $0 }' teams.txt
組合范圍模式和關(guān)系表達式。
將會搜索第四個字段等于31記錄開始,直到第四個字段等于33的所有記錄。然后打印整個記錄$0
。
awk '$4 == 31, $4 == 33 { print $0 }' teams.txt
76ers Philadelphia 51 31 0.622
Celtics Boston 49 33 0.598
特殊表達模式
Awk可以使用的特殊模式是。BEGIN
用于在處理記錄之前執(zhí)行的操作。END
用于在處理記錄后執(zhí)行操作。
BEGIN
模式通常用于聲明變量,END
模式通常用于處理記錄中的數(shù)據(jù),例如統(tǒng)計指定字段的總數(shù)。
如果程序只有BEGIN
模式,則執(zhí)行操作,并且不處理輸入數(shù)據(jù)。如果程序只有END
模式,則在執(zhí)行操作之前先處理輸入。
awk的Gnu版本還包含另外兩個特殊模式BEGINFILE
和ENDFILE
,它們允許您在處理文件時執(zhí)行操作。
在下面的示例中將打印Start Processing.
,然后打印每個記錄的第三個字段,最后打印End Processing.
。這是一個簡單的示例,你也可以用于打印字段的名稱。
awk 'BEGIN { print "Start Processing." }; { print $3 }; END { print "End Processing." }' teams.txt
Start Processing
60
58
51
49
48
End Processing.
組合模式
Awk允許您使用邏輯AND運算符&&
和邏輯或運算符||
組合兩個或多個模式。
例如命令awk '$3 > 50 && $4 < 30 { print $1 }' teams.txt
使用&&
運算符搜索第三字段大于50而第四字段小于30的記錄,然后打印已匹配記錄的第一個字段。
awk '$3 > 50 && $4 < 30 { print $1 }' teams.txt
Bucks
Raptors
內(nèi)置變量
Awk具有許多內(nèi)置變量,這些變量包含非常有用的信息,并允許您控制程序的處理方式。
這是一些最常見的內(nèi)置變量。NF
記錄中的字段總數(shù)。NR
當(dāng)前記錄的編號。FILENAME
當(dāng)前正在處理文件名稱。
FS
字段分隔符。RS
記錄分隔符。OFS
輸出字段分隔符。ORS
輸出記錄分隔符。
AWK變量可以在程序的任何行聲明。要為整個程序定義變量,請將其放在BEGIN
模式中。
例如命令awk 'END { print "File", FILENAME, "contains", NR, "lines." }' teams.txt
。將會打印打印文件名和行數(shù),即記錄總數(shù)。
awk 'END { print "File", FILENAME, "contains", NR, "lines." }' teams.txt
File teams.txt contains 5 lines.
更改字段與記錄分隔符
字段分隔符的默認(rèn)是空格符,你也可以指定為任意數(shù)量的字符,空格,制表符等任何字符。
要修改字段分隔符。可以在awk程序聲明FS
變量來進行修改。也可以使用awk命令的-F
選項更改字段分隔符。
例如命令awk 'BEGIN { FS = "." } { print $1,$2 }' teams.txt
將字段分隔符設(shè)置為.
。awk的-F
選項的等價命令是awk -F "." '{ print $1,$2 }' teams.txt
。
awk 'BEGIN { FS = "." } { print $1,$2 }' teams.txt
awk -F "." '{ print $1,$2 }' teams.txt
Bucks Milwaukee 60 22 0 732
Raptors Toronto 58 24 0 707
76ers Philadelphia 51 31 0 622
Celtics Boston 49 33 0 598
Pacers Indiana 48 34 0 585
記錄分隔符是換行符,可以通過修改RS
變量進行更改。與字段的分隔符一樣你可以指定為任意數(shù)量的字符,空格,制表符等任何字符。
例如命令awk 'BEGIN { RS = "." } { print $1 }' teams.txt
將會修改記錄分隔符為.
。
awk 'BEGIN { RS = "." } { print $1 }' teams.txt
Bucks Milwaukee 60 22 0
732
Raptors Toronto 58 24 0
707
76ers Philadelphia 51 31 0
622
Celtics Boston 49 33 0
598
Pacers Indiana 48 34 0
585
Awk action操作
Awk action操作括在大括號{}
中,并在模式匹配時執(zhí)行。一個操作可以有零個或多個語句。
多個語句按照它們出現(xiàn)的先后順序執(zhí)行,并且必須使用換行符或分號分隔;
。
awk支持幾種類型的語句。 表達式 ,例如變量賦值,算術(shù)運算符,增量和減量運算符。
控制語句 ,用于控制程序的流程if
,for
,while
,switch
。 輸出語句 ,例如print
和printf
。
復(fù)合語句 ,可將其他語句分組。 輸入語句 ,以控制輸入的處理。 Deletion語句 ,刪除數(shù)組元素。
print
語句可能是最常用的awk語句。它打印文本,記錄,字段和變量的格式化輸出。打印多個字段時,需要用逗號分隔。
例如命令awk '{ print $1, $3, $5 }' teams.txt
打印的1,3,5字段用空格分隔。如果您不使用逗號,則字段之間沒有空格,這些字段是串聯(lián)在一起的。
awk '{ print $1, $3, $5 }' teams.txt
awk '{ print $1 $3 $5 }' teams.txt
Bucks 60 0.732
Raptors 58 0.707
76ers 51 0.622
Celtics 49 0.598
Pacers 48 0.585
如果沒有為print
指定參數(shù),默認(rèn)是print $0
,將打印當(dāng)前記錄。要打印自定義文本,文本必須用雙引號引起來。
例如命令awk '{ print "The first field:", $1}' teams.txt
將會打印自定義文本The first field:
和第一個字段。
awk '{ print "The first field:", $1}' teams.txt
The first field: Bucks
The first field: Raptors
The first field: 76ers
The first field: Celtics
The first field: Pacers
您還可以打印特殊字符,例如換行符。
awk 'BEGIN { print "First line\\nSecond line\\nThird line" }'
First line
Second line
Third line
printf語句
為了使您可以更好地控制輸出格式,你可以使用printf
語句。例如命令awk '{ printf "%3d. %s\\n", NR, $0 }' teams.txt
將會為記錄插入行號。
NR
變量是當(dāng)前記錄的編號,將會插入到占位符號%3d
,$0
變量表示當(dāng)前正在處理的記錄,將會插入到占位符號%s
。
printf
不會在每條記錄后創(chuàng)建換行符,因此還在最后使用\\n
換行符,進行對記錄的換行。
awk '{ printf "%3d. %s\\n", NR, $0 }' teams.txt
1. Bucks Milwaukee 60 22 0.732
2. Raptors Toronto 58 24 0.707
3. 76ers Philadelphia 51 31 0.622
4. Celtics Boston 49 33 0.598
5. Pacers Indiana 48 34 0.585
統(tǒng)計字段總和
命令awk '{ sum += $3 } END { printf "%d\\n", sum }' teams.txt
計算記錄中第三字段值的總和。
程序{ sum += $3 }
對第三個字段進行累計,END
模式程序{ printf "%d\\n", sum }
會將sum
變量插入%d
,\\n
是換行符號。
awk '{ sum += $3 } END { printf "%d\\n", sum }' teams.txt
266
運行awk文件
這是一個awk命令的示例awk 'BEGIN { i = 1; while (i < 6) { print "Square of", i, "is", i*i; ++i } }'
。
顯示了如何使用表達式和控制語句來打印從1到5的數(shù)字的平方。
這時單行命令顯得更難理解和維護。在編寫長且復(fù)雜的程序時,您應(yīng)該創(chuàng)建一個單獨的程序文件。
然后使用awk命令的-f
選項指定程序文件,awk
解釋器將會運行指定的文件運行程序。
awk -f prg.awk
BEGIN {
i = 1
while (i < 6) {
print "Square of", i, "is", i*i;
++i
}
}
您還可以在awk的程序文件中使用shebang指令設(shè)置awk
解釋器,程序文件內(nèi)的代碼將會使用awk解釋器運行。
當(dāng)創(chuàng)建awk程序后,保存文件并使用chmod命令使程序文件可執(zhí)行。這樣你就可以直接運行awk程序。
chmod +x prg.awk
./prg.awk
#!/usr/bin/awk -f
BEGIN {
i = 1
while (i < 6) {
print "Square of", i, "is", i*i;
++i
}
}
Awk程序與Shell變量
如果您在Shell程序腳本中使用awk
命令,則很可能需要將Shell程序變量傳遞給awk程序。
一種選擇是用雙引號而不是單引號將程序引起來,并在程序中替換變量。但是,此方式會使您的awk程序更加復(fù)雜,因為您需要對awk變量進行轉(zhuǎn)義。
在awk程序中使用shell變量的推薦方法是將shell變量分配給awk變量。這是一個例子:
num=51
awk -v n="$num" 'BEGIN {print n}'
51
結(jié)論
Awk是最強大的文本處理工具之一。本文幾乎沒有觸及awk編程語言所有知識。要了解awk的更多信息,請查看官方Gawk文檔。
評論
查看更多