AWK介绍
1.awk?簡介
awk?以記錄和字段的方式來查看文本文件
和其他編程語言一樣,?awk?包含變量、條件和循環
awk?能夠進行運算和字符串操作
awk?能夠生成格式化的報表數據
2.awk?概述
awk?程序?awk?命令、括在括號(或寫在文件)中的程序指令以及輸入文件的文件名幾個部分組成。如果沒有輸入文件,輸入則來自于標準輸入。
awk?指令由模式、操作或者模式與操作的組合組成。模式是由某種類型的表達式組成的語句。如果某個表達式中沒有出現關鍵在?if?,但實際在計算時卻暗含?if?這個詞,那么這個表達式就是模式。操作由括在大括號中的一條或多條語句組成,語句之間用分號或者換行符隔開。模式不能括在大括號中,模式由包括在兩個正斜杠之間的正則表達式、一個或多個?awk?操作符組成的表達式組成。
格式:
awk '/search pattern1/ {Actions}
/search pattern2/ {Actions}' file
3.?工作原理
awk?使用一行作為輸入(通過文件或者管道),并將這一行賦給內部變量?$0
行被空格分解為字段(單詞),每一個字段存儲在已編號的變量中,從?$1?開始。(?awk的內部變量?FS?用來確定字段的分隔符。初始時,為空格,包含制表符和空格符)
對于一行,按照給定的正則表達式的順序進行匹配,如果匹配則執行對應的?Action?,如果沒有匹配上則不執行任何動作 ,?Search Pattern?和?Action?是可選的,但是必須提供其中一個 。如果?Search Pattern?未提供,則對所有的輸入行執行?Action?操作。如果?Action?未提供,則默認打印出該行的數據 。?{}?這種?Action?不做任何事情,和未提供的?Action?的工作方式不一樣
打印字段,用?print?、?printf?、?sprintf?,格式:?{ print $1, $3 }?內部變量?output field separator?(?OFS?),默認為空格,?$n?之間的逗號被?OFS?中的字符替換。
輸出之后,從文件中另取一行,并將其復制到?$0?中,覆蓋原來的內容。重復進行……
4.?格式化輸出
print?函數
print?函數用于打印不需要特別編排格式的簡單輸出。更為復雜的格式編排則要使用?printf?和?sprintf。若懂得?C?語言,則也一定懂得如何使用?printf?和?sprintf?。
print?函數的的轉義序列
/b 退格
/f 換頁
/n 換行
/r 回車
/t 制表符
/047 八進制值?47?,即單引號
/c c?代表任意其他字符
打印數字時,可能需要控制數字的格式。可以通過?printf?來實現,但是通過設置一個特殊的變量OFMT?,是用?print?函數也可以控制數字打印格式。?OFMT?默認為“?%.6gd”?,表示只打印小數部分的前?6?位。
例?1?:
long@long-Ubuntu:~$ awk 'BEGIN { OFMT="%.2f"; print 1.2456789, 12E-2 }'
1.25 0.12
printf?函數
printf?函數返回一個帶格式的字符串給標準輸出,如同?C?語言中的?printf?語句。?printf?語句包括一個加引號的控制串,控制串中可能嵌套有若干格式說明和修飾符。控制串后面跟逗號,之后是一列由逗號分隔的表達式。與?print?函數不同的是,?printf?函數不會在行尾自動換行。若要換行,在控制串中提供轉義字符?/n?。每個百分號和格式說明都必須有一個對應的變量?。要打印百分號就必須在控制串中給出兩個百分號。
p?rintf?函數的轉義字符
c? 字符
s? 字符串
d? 十進制整數
ld 十進制長整數
u? 十進制無符號整數
lu 十進制無符號長整數
x? 十六進制整數
lx 十六進制長整數
o? 八進制整數
lo 八進制長整數
e? 用科學計數法表示浮點數
f? 浮點數
g? 選用?e?或?f?中較短的一種形式
?
printf?函數的修飾符
- 左對齊修飾符
# 顯示八進制整數時,前面加 0 ,顯示十六進制整數時,前面加 0x
+ 顯示使用 d 、 e 、 f 、 g 轉換的整數時,加上正負號
0 用 0 而不是空白符來填充所顯示的值
printf?函數控制串里的管道符(豎杠)是文本的一部分,用于指示格式的起始與結束。
例?2?:
long@long-Ubuntu:~$ echo "UNIX" | awk ' { printf "|%-15s|/n", $1 }'
|UNIX |
long@long-Ubuntu:~$ echo "UNIX" | awk ' { printf "|%15s|/n", $1 }'
| UNIX|
(?%15s?表示占?15?個字符的字符串)
5.?文件中的?awk?命令
如果?awk?命令寫在文件里,用?-f?選項制定?awk?的文件名,后面加上要處理的輸入文件的文件名。awk?從緩沖區讀入一條指令,接著測試?awk?文件中的每一條命令,然后對讀入的記錄執行命令。
例?3?:
long@long-Ubuntu:~$ cat employees
Tom Jones 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
long@long-Ubuntu:~$ cat awkfile
/^Mary/ {print "Hello Mary!"}
{print $1, $2, $3}
long@long-Ubuntu:~$ awk -f awkfile employees
Tom Jones 4424
Hello Mary!
Mary Adams 5346
Sally Chang 1654
6.?記錄與字段
在?awk?看來,輸入數據具有格式和結構。默認情況下,每一行稱為一條記錄,以換行符結束。
默認情況下,輸入和輸出記錄的分隔符(行分隔符)都是回車符(換行符),分別保存在?awk?的內置變量?ORS?和?RS?中,其值可以修改,只能以特定方式進行修改。
每條記錄的記錄號都保存在?awk?的內置變量?NR?中,每處理完一條記錄,?NR?的值加?1?。
每條記錄由字段(?field?)組成,用空白符(空格或制表符)分隔。內置變量?NF?保存記錄的字符數。前面提到的?FS?,用來分隔字段,并且刪除各字段前多余的空白或制表符。可以在?BEGIN?語句中或命令行上賦值來改變?FS?的值。也可以在命令行上通過?-F?選項來改變?FS?的值。
例?4?:
long@long-Ubuntu:~$ cat employees2
Tom Jones:4424:5/12/66:543354
Mary Adams:5346:11/4/63:28765
Sally Chang:1654:7/22/54:650000
Billy Black:1683:9/23/44:336500
long@long-Ubuntu:~$ awk -F: '/Tom Jones/{print $1,$2}' employees2
Tom Jones 4424
也可以使用多個字段分隔符。此時?FS?對應的是一個正則表達式字符串,被括在方括號中。
例?5?:
long@long-Ubuntu:~$ awk -F'[ :/t]' '{print $1,$2}' employees
Tom Jones
Mary Adams
Sally Chang
Billy Black
long@long-Ubuntu:~$ awk -F'[ :/t]' '{print $1,$2}' employees2
Tom Jones
Mary Adams
Sally Chang
Billy Black
前面提到的輸出字段分隔符?OFS?,輸出時如果沒有用逗號來分隔字段,結果中字段將堆在一起。OFS?的值也可以改變。
7.?模式與操作
模式由正則表達式、判別條件真偽的表達式或者二者的組合構成。?awk?默認打印所有是表達式結果為真的文本行。模式表達式中暗含著?if?語句,如此,就不必用花括號將它括起來。當?if?是顯式給出時,這個表達式就成了操作語句,語法將不一樣
操作是花括號中以分號分隔的語句。若操作前有模式,則該模式控制執行操作的時機。
正則表達式
/?取消字符的特殊含義
^?在行首匹配。?^?不能用于匹配嵌套在一個字符串中的行首,?if ("line1/nLINE 2" ~ /^L/) ...?不為真。
$?在行尾匹配。?$?不能用于匹配嵌套在一個字符串中的行尾,?if ("line1/nLINE 2" ~ /1$/) ...?不為真
.?匹配單個任意字符,包括換行符。
[...]?匹配制定字符組中的任意一個。
[^ …]?匹配任何一個不在制定字符組中的字符
|?匹配?|?兩側的任意的字符(組),在所有的正則表達式中優先級最低。?The alternation applies to the largest possible regexps on either side.
(...) Parentheses are used for grouping in regular expressions, as in arithmetic. They can be used to concatenate regular expressions containing the alternation operator.
*?匹配零個或者多個前導字符
+?匹配一個或者多個前導字符
??匹配零個或者多個前導字符
{n} ,{n,} ,{n,m} One or two numbers inside braces denote an interval expression. If there is one number in the braces, the preceding regexp is repeated n times. If there are two numbers separated by a comma, the preceding regexp is repeated n to m times. If there is one number followed by a comma, then the preceding regexp is repeated at least n times:
wh{3}y
Matches ‘whhhy’, but not ‘why’ or ‘whhhhy’.
wh{3,5}y
Matches ‘whhhy’, ‘whhhhy’, or ‘whhhhhy’, only.
wh{2,}y
Matches ‘whhy’ or ‘whhhy’, and so on.
Interval expressions were not traditionally available in awk. They were added as part of the POSIX standard to make awk and egrep consistent with each other.
However, because old programs may use ‘{’ and ‘}’ in regexp constants, by default gawk does not match interval expressions in regexps. If either --posix or --re-interval are specified, then interval expressions are allowed in regexps.
For new programs that use ‘{’ and ‘}’ in regexp constants, it is good practice to always escape them with a backslash. Then the regexp constants are valid and work the way you want them to.
正則表達式中 ‘?*’,?,‘?+’?, ‘??’?以及‘?{’?和 ‘?}’?有最高的優先級,解析來是連接操作符,最后是‘?|’.算術中一樣,括號可以用來改變順序。
在?POSIX awk?和?gawk?中,如果正則表達式里?'*'?,?'+'?,?'?'?前面沒有任何字符,那么這三個字符代表他們自己。很多其他版本的?awk?中,將把這視為錯誤。
gawk?-Specific Regexp Operators
/Y?匹配一個單詞開頭或者末尾的空字符串。
/B?匹配單詞內的空字符串。
/<?匹配一個單詞的開頭的空字符串,錨定開始。
/>?匹配一個單詞的末尾的空字符串,錨定末尾。
/w?匹配一個字母數字組成的單詞。
/W?匹配一個非字母數字組成的單詞。
/‘?匹配字符串開頭的一個空字符串。
/'?匹配字符串末尾的一個空字符串。
The various command-line options control how?gawk?interprets characters in regexps:
Nooptions :
In the default case, gawk provides all the facilities of POSIX regexps and the previously described GNU regexp operators. GNU regexp operators described in Regexp Operators. However, interval expressions are not supported.
--posix :
Only POSIX regexps are supported; the GNU operators are not special (e.g., ‘/w’ matches a literal ‘w’). Interval expressions are allowed.
--traditional :
Traditional Unix awk regexps are matched. The GNU operators are not special, interval expressions are not available, nor are the POSIX character classes ([[:alnum:]], etc.). Characters described by octal and hexadecimal escape sequences are treated literally, even if they represent regexp metacharacters. Also, gawk silently skips directories named on the command line.
--re-interval :
Allow interval expressions in regexps, even if --traditional has been provided. (--posix automatically enables interval expressions, so --re-interval is redundant when --posix is is used.)
POSIX?增加的括號字符類
Class Meaning
[:alnum:] Alphanumeric characters.
[:alpha:] Alphabetic characters.
[:blank:] Space and TAB characters.
[:cntrl:] Control characters.
[:digit:] Numeric characters.
[:graph:] Characters that are both printable and visible.
[:lower:] Lowercase alphabetic characters.
[:print:] Printable characters (characters that are not control characters).
[:punct:] Punctuation characters
[:space:] Space characters (such as space, TAB, and formfeed, to name a few).
[:upper:] Uppercase alphabetic characters.
[:xdigit:] Characters that are hexadecimal digits.
9.?范圍模板
范圍模板匹配從第一個模板的第一次出現到第二個模板的第一次出現之間所有行。如果有一個模板沒?出現,則匹配到開頭或末尾。如?$ awk '/root/,/mysql/' test?將顯示?root?第一次出現到?mysql第?一次出現之間的所有行。
10.?關系運算符
<?,?<=?,?==?,?!=?,?>=?,?>?,?~?,?!~?(最后兩個表示匹配和不匹配正則表達式)
11.?條件表達式
條件表達式?1 ??條件表達式?2 :?條件表達式?3
12.?算術運算
可以在模式中進行計算,?awk?都將按浮點方式執行運算。支持:?+?,?-?,?*?,?/?,?%?,?^(冪)
13.?邏輯操作符與復合模式
&&?,?||?,!
例?6?:?一個驗證?passwd?文件有效性的例子
long@long-Ubuntu:~$ cat /etc/passwd | awk -F: '/
> NF != 7 {/
> printf("line %d, does not have 7 fields:%s/n",NR,$0)}/
> $1 !~ /[A-Za-z0-9]/{printf("line %d, non alpha and numeric user id:%d: %s/n",NR,$0)}/
> $2 == "*" {printf("line %d, no password: %s/n", NR,$0)}'
1 cat?把結果輸出給?awk?,?awk?把域之間的分隔符設為冒號。
2?如果域的數量?(NF)?不等于?7?,就執行下面的程序。
3 printf?打印字符串?"line ?? does not have 7 fields"?,并顯示該條記錄。
4?若第一個域沒包含任何字母和數字,?printf?打印“?no alpha and numeric user id"?,并顯示記錄數和記錄。
5?如果第二個域是一個星號,就打印字符串“?no passwd”?,緊跟著顯示記錄數和記錄本身。
例?7?:幾個示例:
$ awk '/^(no|so)/' filename-----?打印所有以模式?no?或?so?開頭的行。
$ awk '/^[ns]/{print $1}' filename-----?如果記錄以?n?或?s?開頭,就打印這個記錄。
$ awk '$1 ~/[0-9][0-9]$/(print $1}' filename-----?如果第一個域以兩個數字結束就打印這個記錄。
$ awk '$1 == 100 || $2 < 50' filename-----?如果第一個或等于?100?或者第二個域小于?50,則打印該行。
$ awk '$1 != 10' filename-----?如果第一個域不等于?10?就打印該行。
$ awk '/test/{print $1 + 10}' filename-----?如果記錄包含正則表達式?test?,則第一個域加10?并打印
$ awk '{print ($1 > 5 ? "ok "$1: "error"$1)}' filename—---?如果第一個域大于?5?則打印問號后面?的表達式值,否則打印冒號后面的表達式值。
$ awk '/^root/,/^mysql/' filename----?打印從以正則表達式?root?開頭的記錄到以正則表達式?mysql?開頭?的記錄范圍內的所有記錄。如果找到一個新的正則表達式?root?開頭的記錄,則繼續打印直到下一個以正則?表達式?mysql?開頭的記錄為止,或到文件末尾。
14.?變量
在?awk?中,變量不需要定義就可以直接使用,變量類型可以是數字或字符串,由?awk?根據上下文推導,不用指定
變量名可以包括字母、數字和下劃線,但不能以數字開頭。
賦值格式:?Variable = expression
變量被設置后,就變成與等號右邊那個表達式相同的類型。
未經初始化的變量的值是?0?或者“”,具體是哪個取決于它們被使用時的上下文。
將一個字符串強制轉換為數字,方法為:?name+0
將數字轉換成字符串的方法是:?number “”
賦值運算符:?=?,?+=?,?-=?,?*=?,?/=?,?%=?,?^=
遞增遞減運算符,也分為前置和后置兩種,遵循的規則與?C?語言中一樣
awk?可以在命令行中給變量賦值,然后將這個變量傳輸給?awk?腳本。如?$ awk -F: -f awkscript month=4 year=2004 filename?,上式的?month?和?year?都是自定義變量,分別被賦值為?4?和2004?。在?awk?腳本中,這些變量使用起來就象是在腳本中建立的一樣。注意,如果命令行中filename?的位置在變量之前,那么在?BEGIN?語句中的變量就不能被使用(參見后面的?BEGIN?模式)。
-v?選項,?awk?的?-v?選項允許在?BEGIN?語句中,處理命令行變量。從命令行傳遞的每一個變量前面都必須加?-v?選項
字段變量也可被賦值和修改。新的字段可以通過賦值來創建。字段變量引用的字段如果沒有值,則被賦值為空串(即如果只有?4?個字段,但是對?$6?復制,那么不存在的?$5?被賦值為空串)。字段的值發生變化時,?awk?會以?OFS?的值作為字段間隔符重新計算?$0?的值。字段數目通常在?100?以內。如?$ awk '{$2 = 100 + $1; print }' test,?上式表示,如果第二個域不存在,?awk?將計算表達式100?加?$1?的值,并將其賦值給?$2?,如果第二個域存在,則用表達式的值覆蓋?$2?原來的值。
內建變量
$n?當前記錄的第?n?個字段,字段間由?FS?分隔。
$0?完整的輸入記錄。
ARGC?命令行參數的數目。
ARGIND?命令行中當前文件的位置?(?從?0?開始算?)?。
ARGV?包含命令行參數的數組。
CONVFMT?數字轉換格式?(?默認值為?%.6g)
ENVIRON?環境變量關聯數組。
ERRNO?最后一個系統錯誤的描述。
FIELDWIDTHS?字段寬度列表?(?用空格鍵分隔?)?。
FILENAME?當前文件名。
FNR?同?NR?,但相對于當前文件。
FS?字段分隔符?(?默認是任何空格?)?。
IGNORECASE?如果為真(即非?0?值),則進行忽略大小寫的匹配。
NF?當前記錄中的字段數。
NR?當前記錄數。
OFMT?數字的輸出格式?(?默認值是?%.6g)?。
OFS?輸出字段分隔符?(?默認值是一個空格?)?。
ORS?輸出記錄分隔符?(?默認值是一個換行符?)?。
RLENGTH?由?match?函數所匹配的字符串的長度。
RS?記錄分隔符?(?默認是一個換行符?)?。
RSTART?由?match?函數所匹配的字符串的第一個位置。
SUBSEP?數組下標分隔符?(?默認值是?/034)?。
15.?BEGIN?模式
BEGIN?模式后面跟一個操作塊。?awk?必須在對輸入文件進行任何處理之前,先執行該操作塊。常被用于修改內置變量的值,為用戶自定義變量賦初值和打印輸出的頁眉或者標題。。
例?8?:
$ awk 'BEGIN{FS=":"; OFS="/t"; ORS="/n/n"}{print $1,$2,$3} filename?。上式表示,在?處理輸入?文件以前,域分隔符?(FS)?被設為冒號,輸出文件分隔符?(OFS)?被設置為制表符,輸出記錄分隔符?(ORS)?被設?置為兩個換行符。?$ awk 'BEGIN{print "TITLE TEST"}?只打印標題。
編寫?awk?腳本時,可以先測試好?BEGIN?塊操作,再寫程序的其他部分。
16.?END?模式
END?模式不匹配任何輸入行,而是執行任何與之關聯的操作。?Awk?處理完所有輸入行之后才處理END?模式。
例?9?:
$ awk 'END{print "The number of records is" NR}' test?,上式將打印所有被處理的記錄數。
17.?重定向和管道
awk?可使用?shell?的重定向符進行重定向輸出
輸入重定向需用到?getline?函數。?getline?從標準輸入、管道或者當前正在處理的文件之外的其他輸入文件獲得輸入。它負責從輸入獲得下一行的內容,并給?NF,NR?和?FNR?等內建變量賦值。如果得到一條記錄,?getline?函數返回?1?,如果到達文件的末尾就返回?0?,如果出現錯誤,例如打開文件失敗,就返回?-1?。
例?10?:
$ awk 'BEGIN{ "date" | getline d; print d}' filename
執行?linux?的?date?命令,并通過管道輸出給?getline?,然后再把輸出賦值給自定義變量?d?,并打印它。
$ awk 'BEGIN{"date" | getline d; split(d,mon); print mon[2]}' filename
執行?shell?的?date?命令,并通過管道輸出給?getline?,然后?getline?從管道中讀取并將輸入賦值給d?,?split?函?數把變量?d?轉化成數組?mon?,然后打印數組?mon?的第二個元素。
$ awk 'BEGIN{while( "ls" | getline) print}'
命令?ls?的輸出傳遞給?getline?作為輸入,循環使?getline?從?ls?的輸出中讀取一行,并把它打印到屏幕。這里沒有?輸入文件,因為?BEGIN?塊在打開輸入文件前執行,所以可以忽略輸入文件。
$ awk 'BEGIN{while (getline < "/etc/passwd" > 0) lc++; print lc}'
awk?將逐行讀取文件?/etc/passwd?的內容,在到達文件末尾前,計數器?lc?一直增加,當到末尾時,打印?lc?的值。?注意,如果文件不存在,?getline?返回?-1?,如果到達文件的末尾就返回?0?,如果讀到一行,就返回?1?,所以命令?while (getline < "/etc/passwd")?在文件不存在的情況下將陷入無限循環,因為返回?-1?表示邏輯真。
如果在?awk?程序中打開了管道?,就必須先關閉它才能打開另一個管道。管道符右邊的命令被括在雙引號之間。每次只能打開一個管道。如果打算再次在?awk?程序中使用某個文件或管道進行讀寫,則可能要先關閉程序,因為其中的管道會保持打開狀態直至腳本運行結束。注意:管道一旦被打開,就會保持打開狀態直至?awk?退出。?END?塊中的語句也會受到管道影響。通過?close()?可關閉管道
例?11?:
(腳本)
{ print $1,$2,$3 | “sort -r +1 -2 +0 -1” }
END{
close(“sort -r +1 -2 +0 -1”)
<rest of statements> }
awk?內置函數?system?以?Linux?系統命令作為參數,執行該命令并將命令的退出狀態返回給?awk?程序。作為參數的命令必須加雙引號。
18.?條件語句
awk?條件語句源于?C?語言,可以用他們對包含判斷語句的程序進行控制。
if?語句
格式?: {if (expression){
statement; statement; ...
}
}
例?12?:
$ awk '{if ($1 <$2) print $2 "too high"}' test
如果第一個域小于第二個域則打印。
$ awk '{if ($1 < $2) {count++; print "ok"}}' test
如果第一個域小于第二個域,則?count?加?1?,并打印?ok?。
if/else?語句
格式:?{if (expression){
statement; statement; ...
}
else{
statement; statement; ...
}
}
例?13?:
$ awk '{if ($1 > 100) print $1 "bad" ; else print "ok"}' test
如果?$1?大?100?則打印?$1 bad,?否則打印?ok?。
$ awk '{if ($1 > 100){ count++; print $1} else {count--; print $2}' test
如果?$1?大于?100?,則?count?加一,并打印?$1?,否則?count?減一,并打印?$1?。
if/else else if?語句
格式:?{if (expression){
statement; statement; ...
}
else if (expression){
statement; statement; ...
}
else if (expression){
statement; statement; ...
}
else {
statement; statement; ...
}
}
19.?循環語句
常常用來對記錄中的每個字段重復執行某些操作?,或者在?END?塊中用來循環處理某個數組中的所有元素。三種類型的循環:?while?循環,?for?循環,特殊?for?循環
while?循環
第一步給一個變量賦初值,在?while?中測試該變量,若值為真(非?0?),則進入循環執行語句。do while?循環與?while?類似,唯一的區別是?do while?至少執行一次循環體,然后才測試表達式。
例?14?:
$ awk '{ i = 1; while ( i <= NF ) { print NF,$i; i++}}' test
變量的初始值為?1?,若?i?小于可等于?NF(?記錄中域的個數?),?則執行打印語句,且?i?增加?1?。直到?i的值大于?NF.
for?循環
for?循環的圓括號中需要?3?個表達式,前兩個分別是初始化和測試表達式,第?3?個用于更新測試表達式所用的變量。注意,?for?循環中,第一條語句只能初始化一個變量(這與?C?語言不同)
例?15?:
$ awk '{for (i = 1; i<NF; i++) print NF,$i}' test?。作用同上。
循環控制
break?語句用于在滿足條件的情況下跳出循環
continue?語句用于在滿足條件的情況下忽略后面的語句,直接返回循環的頂端。
例?16?:
1. {for ( x=3; x<=NF; x++)
if ($x<0){print "Bottomed out!"; break}}
2. {for ( x=3; x<=NF; x++)
if ($x==0){print "Get next item"; continue}}
20.?程序控制語句
next?語句,從輸入文件中取出下一行輸入,然后從?awk?腳本的頂部重新開始執行。
exit?語句,用于終止?awk?程序。它只能中斷對記錄的處理,不能跳過?END?語句。若?exit?語句的參數是一個?0~255?之間的值,這個值會被打印在命令行上,以表明程序是否執行成功?,并指出失敗類型。
21.?數組
數組在?awk?中被稱為關聯數組?(?associative arrays?),其下表既可以是字符串也可以是數字。數組的鍵和值都存儲在?awk?程序內部的一個表中,該表采用的是?散列算法,所以數組元素不是順序存儲的。數組也是被用到時才被創建。?awk?還能判定數組用于保存數字還是字符串,根據上下文被初始化為?0?或者空字符串。數組大小不需要聲明。
用變量作為數組下標。
例?17?:
$ awk {name[x++]=$2};END{for(i=0;i<NR;i++) print i,name[i]}' test
數組?name?中的下標是一個自定義變量?x?,?awk?初始化?x?的值為?0?,在每次使用后增加?1?。第二個域的值被賦給?name?數組的各個元素。在?END?模塊中,?for?循環被用于循環整個數組,從下標為?0?的元素開始,打印那些存儲在數組中的值。因為下標是關健字,所以它不一定從?0?開始,可以從任何值開始。
特殊?for?循環
當下標為字符串或者非連續的數字時,不能用?for?循環來遍歷數組。這是就要使用特殊的?for?循環。
格式:?(?for?(?item in arrayname) {
print arrayname[item]
}
}
用字符串作為數組下標
數組下表可以由包含單個字符或字符串的變量組成,如果是字符串,就必須用雙引號括起來。
用字段的值作為數組下標
例?18?:
long@long-Ubuntu:~$ cat datafile1
4234 Tom 43
4567 Arch 45
2008 Eliza 65
4571 Tom 22
3298 Eliza 21
4622 Tom 53
2345 Mary 24
long@long-Ubuntu:~$ awk '{count[$2]++}END{for(name in count)print name, / count[name]}' dataf ile1
Arch 1
Tom 3
Eliza 2
Mary 1
統計文件中某個字段出現的次數
數組與函數
awk?的內置函數?split?能夠將字符串拆分為?詞,然后保存在數組中。
格式:?split?(字符串,數組,字段分隔符)
split?(字符串,數組)
awk?的內置函數?delete?用于刪除數組元素
多維數組
awk?定義多為數組?的方法是把多個下標串成字符串,下標之間用內置變量?SUBSEP?的值分隔。變量?SUBSEP?的值默認為“?/034”?,這是個不可打印的字符,不太可能用作下標中的字符。
例?19?:
long@long-Ubuntu:~$ cat datafile2
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
6 7 8 9 10
long@long-Ubuntu:~$ awk '{nf=NF
for(x=1; x<=NF; x++){
matrix[NR,x] = $x
}
}END{
for(x=1;x<=NR;x++){
for(y=1;y<=nf;y++)
printf "%d/t", matrix[x,y]
printf "/n"
}
}' datafile2
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
6 7 8 9 10
22.?處理命令行參數
awk?可以從內置數組?ARGV?中得到命令行參數,其中包括命令?awk?。但所有傳遞給?awk?的選項不再其中。?ARGV?數組下標從?0?開始。?ARGC?是一個包含命令行參數個數的內置變量。
23.awk?的內置函數
字符串函數
sub?函數匹配記錄中最大、最靠左邊的子字符串的正則表達式,并用替換字符串替換這些字符串。如果沒有指定目標字符串就默認使用整個記錄。替換只發生在第一次匹配的時候。
格式:?sub (regular expression, substitution string):
sub (regular expression, substitution string, target string)
例?20?:
$ awk '{ sub(/test/, "mytest"); print }' testfile
$ awk '{ sub(/test/, "mytest"); $1}; print }' testfile
第一個例子在整個記錄中匹配,替換只發生在第一次匹配發生的時候
第二個例子在整個記錄的第一個域中進行匹配,替換只發生在第一次匹配發生的時候。
gsub?函數作用如?sub?,但它在整個文檔中進行匹配。
格式:?gsub (regular expression, substitution string)
gsub (regular expression, substitution string, target string)
index?函數返回子字符串第一次被匹配的位置,偏移量從位置?1?開始。
格式:?index(string, substring)
length?函數返回記錄的字符數,若未指定參數,則?length?函數返回記錄中的字符個數
格式:?length( string )
length
substr?函數返回從字符串指定位置開始的子字符串,如果指定長度超過實際長度,就返回其實際內容。
格式:?substr( string, starting position )
substr( string, starting position,?子串長度?)
match?函數返回在字符串中正則表達式位置的索引,如果找不到指定的正則表達式則返回?0?。match?函數把內置變量?RSTART?設為子串在字符串中的起始位置,?RLENGTH?為則設為子串的長度。這些變量可以被?substr?函數用來提取相應模式的子串。
格式:?match( string, regular expression )
例?21?:
$ awk '{start=match("this is a test",/[a-z]+$/); print start}' filename
$ awk '{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'/ filename
第一個實例打印以連續小寫字符結尾的開始位置,這里是?11?。
第二個實例還打印?RSTART?和?RLENGTH?變量,這里是?11(start)?,?11(RSTART)?,4(RLENGTH)?。
toupper?和?tolower?函數可用于字符串大小間的轉換,該功能只在?gawk?中有效。
格式:?toupper( string )
tolower( string )
split?函數可按給定的分隔符把字符串分割為一個數組。如果分隔符沒提供,則按當前?FS?值進行分割。
格式:?split( string, array, field separator )
split( string, array )
例?22?:
$ awk '{ split( "20:18:00", time, ":" ); print time[2] }' filename
把時間按冒號分割到?time?數組內,并顯示第二個數組元素?18?。
sprintf?函數?返回一個指定格式的表達式。可以在?sprintf?函數中使用?printf?函數的格式規范
格式:?variable=sprintf(“?含有格式說明的字符串”?,?表達式?1,?表達式?2?,?..,?表達式?n)
內置算術函數
int(x)
returns nearest integer to x, located between x and zero and truncated toward zero.
sqrt(x)
returns the positive square root of x. gawk reports an error if x is negative.
exp(x)
returns the exponential of x (e ^ x) or reports an error if x is out of range.
log(x)
returns the natural logarithm of x, if x is positive; otherwise, it reports an error.
sin(x)
returns the sine of x, with x in radians.
cos(x)
returns the cosine of x, with x in radians.
atan2(y, x)
returns the arctangent of y / x in radians.
rand()
returns a random number?,?uniformly distributed between zero and one?(?0<=value<1)
srand?(?x)
function?srand?sets the seed, for generating random numbers to the value x
時間函數
systime?函數返回從?1970?年?1?月?1?日開始到當前時間?(?不計閏年?)?的整秒數。
格式:?systime()
strftime?函數使用?C?庫中的?strftime?函數格式化時間。
日期和時間格式說明符
格式?描述
%a 星期幾的縮寫?(Sun)
%A 星期幾的完整寫法?(Sunday)
%b 月名的縮寫?(Oct)
%B 月名的完整寫法?(October)
%c 本地日期和時間
%d 十進制日期
%D 日期?08/20/99
%e 日期,如果只有一位會補上一個空格
%H 用十進制表示?24?小時格式的小時
%I 用十進制表示?12?小時格式的小時
%j 從?1?月?1?日起一年中的第幾天
%m 十進制表示的月份
%M 十進制表示的分鐘
%p 12?小時表示法?(AM/PM)
%S 十進制表示的秒
%U 十進制表示的一年中的第幾個星期?(?星期天作為一個星期的開始?)
%w 十進制表示的星期幾?(?星期天是?0)
%W 十進制表示的一年中的第幾個星期?(?星期一作為一個星期的開始?)
%x 重新設置本地日期?(08/20/99)
%X 重新設置本地時間?(12?:?00?:?00)
%y 兩位數字表示的年?(99)
%Y 當前月份
%Z 時區?(PDT)
%% 百分號?(%)
格式:?strftime( [format specification][,timestamp] )
24.?用戶自定義函數
腳本中凡是可以出現模式操作規則的位置都可以放置用戶自定義的函數。
格式:?函數名?(?參數?,?參數?,?參數?, ...){
語句
return?表達式
(?注:?return?語句和表達式都是可選項?)
}
變量以參數值的方式傳遞,且僅在使用它的函數中局部有效。函數使用的只是變量的副本。數組則通過地址或引用被傳 遞,因此,可以在函數中直接修改數組的元素。函數中的變量只要不是從參數列表傳來的,都視為全局變量。調用函數時,如果沒有指定某個形參的值,該參數被初 始化為空。
例?23?:
long@long-Ubuntu:~$ cat grades
44 55 66 22 77 99
100 22 77 99 33 66
55 66 100 99 88 45
long@long-Ubuntu:~$ cat sorter.sc
#Scriptname: sorter
#It sorts numbers in ascending order
function sort(scores, num_elements, temp, i, j){
#temp,i,j will be local and private
#with an initial value of null
for(i=2; i<=num_elements; ++i){
for(j=i; scores[j-1]>scores[j]; --j){
temp = scores[j]
scores[j] = scores[j-1]
scores[j-1] = temp
}
}
}
{for (i=1; i<=NF; i++)
grades[i] = $i
?
sort(grades,NF)
for(j=1;j<NF;++j)
printf("%d ", grades[j])
printf("/n")
}
long@long-Ubuntu:~$ awk -f sorter.sc grades
22 44 55 66 77
22 33 66 77 99
45 55 66 88 99
25.?雜項
固定字段
有些數據沒有明顯的字段分隔符,卻有固定寬度的列。預處理這些數據時,?substr?很有用
空字段
用固定長度的字段來存儲數據,就可能出現一些空字段,?substr?可以被用來保存字段,而不考慮它們是否包含數據
26.awk?命令選項
-F fs or --field-separator fs
指定輸入文件折分隔符,?fs?是一個字符串或者是一個正則表達式,如?-F:?。
-v var=value or --asign var=value
賦值一個用戶定義變量。
-f scripfile or --file scriptfile
從腳本文件中讀取?awk?命令。
-mf nnn and -mr nnn
對?nnn?值設置內在限制,?-mf?選項限制分配給?nnn?的最大塊數目;?-mr?選項限制記錄的最大數目。這兩個功能是?Bell?實驗室版?awk?的擴展功能,在標準?awk?中不適用。
-W compact or --compat, -W traditional or --traditional
在兼容模式下運行?awk?。所以?gawk?的行為和標準的?awk?完全一樣,所有的?awk?擴展都被忽略。
-W copyleft or --copyleft, -W copyright or --copyright
打印簡短的版權信息。
-W help or --help, -W usage or --usage
打印全部?awk?選項和每個選項的簡短說明。
-W lint or --lint
打印不能向傳統?unix?平臺移植的結構的警告。
-W lint-old or --lint-old
打印關于不能向傳統?unix?平臺移植的結構的警告。
-W posix
打開兼容模式。但有以下限制,不識別:?/x?、函數關鍵字、?func?、換碼序列以及當?fs?是一個空格時,將新行作為一個域分隔符;操作符?**?和?**=?不能代替?^?和?^=?;?fflush?無效。
-W re-interval or --re-inerval
允許間隔正則表達式的使用,參考?(grep?中的?Posix?字符類?)?,如括號表達式?[[:alpha:]]?。
-W source program-text or --source program-text
使用?program-text?作為源代碼,可與?-f?命令混用。
-W version or --version
打印?bug?報告信息的版本。
?
http://blog.csdn.net/longwen7/article/details/6336757
總結