linux命令终极系列awk
AWK man 手冊:http://man.linuxde.net/awk
AWK編程的內容極多,這里只羅列簡單常用的用法,更多請參考?http://www.gnu.org/software/gawk/manual/gawk.html
簡介
什么是awk??
? ? ? ? awk是一個強大的文本分析工具,相對于grep的查找,sed的編輯,awk在其對數據分析并生成報告時,顯得尤為強大。簡單來說,awk就是把文件逐行的讀入,以空格為默認分隔符將每行切片,切開的部分再進行各種分析處理。即awk處理過程: 依次對每一行進行處理,然后輸出。
? ? ? ? awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk,gawk 是 AWK 的 GNU 版本。
? ? ? ? awk其名稱得自于它的創始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母。正是這三個人創造了awk---一個優秀的樣式掃描與處理工具。實際上 AWK 的確擁有自己的語言: AWK 程序設計語言, 三位創建者已將它正式定義為“樣式掃描和處理語言”。?它允許您創建簡短的程序,這些程序讀取輸入文件、為數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其他的功能。
AWK的功能是什么?
? ? ? ? 與sed和grep很相似,awk是一種樣式掃描與處理工具。但其功能卻大大強于sed和grep。awk提供了極其強大的功能:它幾乎可以完成grep和sed所能完成的全部工作,同時,它還可以可以進行樣式裝入、流控制、數學運算符、進程控制語句甚至于內置的變量和函數。它具備了一個完整的語言所應具有的幾乎所有精美特性。實際上,awk的確擁有自己的語言:awk程序設計語言,awk的三位創建者已將它正式定義為:樣式掃描和處理語言。
為什么使用awk?
? ? ? ? 使用awk的第一個理由是基于文本的樣式掃描和處理是我們經常做的工作,awk所做的工作有些象數據庫,但與數據庫不同的是,它處理的是文本文件,這些文件沒有專門的存儲格式,普通的人們就能編輯、閱讀、理解和處理它們。而數據庫文件往往具有特殊的存儲格式,這使得它們必須用數據庫處理程序來處理它們。既然這種類似于數據庫的處理工作我們經常會遇到,我們就應當找到處理它們的簡便易行的方法,UNIX有很多這方面的工具,例如sed 、grep、sort以及find等等,awk是其中十分優秀的一種。?
? ? ? ? 使用awk的第二個理由是awk是一個簡單的工具,當然這是相對于其強大的功能來說的。的確,UNIX有許多優秀的工具,例如UNIX天然的開發工具C語言及其延續C++就非常的優秀。但相對于它們來說,awk完成同樣的功能要方便和簡捷得多。這首先是因為awk提供了適應多種需要的解決方案:從解決簡單問題的awk命令行到復雜而精巧的awk程序設計語言,這樣做的好處是,你可以不必用復雜的方法去解決本來很簡單的問題。例如,你可以用一個命令行解決簡單的問題,而C不行,即使一個再簡單的程序,C語言也必須經過編寫、編譯的全過程。其次,awk本身是解釋執行的,這就使得awk程序不必經過編譯的過程,同時,這也使得它與shell script程序能夠很好的契合。最后,awk本身較C語言簡單,雖然awk吸收了C語言很多優秀的成分,熟悉C語言會對學習awk有很大的幫助,但awk本身不須要會使用C語言――一種功能強大但需要大量時間學習才能掌握其技巧的開發工具。
基于以上理由,再加上awk強大的功能,我們有理由說,如果你要處理與文本樣式掃描相關的工作,awk應該是你的第一選擇。在這里有一個可遵循的一般原則:如果你用普通的shell工具或shell script有困難的話,試試awk,如果awk仍不能解決問題,則便用C語言,如果C語言仍然失敗,則移至C++。?
AWK調用方式
有三種方式調用awk
AWK語法
基本語法 awk [opion] 'awk_script' input_file1 [input_file2 ...] awk的常用選項option有:-F fs : 使用fs作為輸入記錄的字段分隔符,如果省略該選項,awk使用環境變量IFS的值-f filename : 從文件filename中讀取awk_script-v var=value : 為awk_script設置變量awk '{pattern + action}' {filenames} awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file [-F|-f|-v] 大參數,-F指定分隔符,-f調用腳本,-v定義變量 var=value ' ' 引用代碼塊 BEGIN 初始化代碼塊,在對每一行進行處理之前,初始化代碼,主要是引用全局變量,設置FS分隔符 // 匹配代碼塊,可以是字符串或正則表達式 {} 命令代碼塊,包含一條或多條命令 ; 多條命令使用分號分隔 END 結尾代碼塊,在對每一行進行處理之后再執行的代碼塊,主要是進行最終計算或輸出結尾摘要信息 file awk的輸入文件,可以有多個。注意:awk不會修改輸入文件。如果沒有指定輸入文件,那么默認為標準輸入(屏幕)awk的變量
awk提供兩種變量:
(1) 內置變量
在引用時,不需要加$
(2) 自定義變量
? ? ? ? awk中引用自定義變量必須在它前面加上標志符"$"。awk根據其在awk中第一次出現的形式和上下文確定其具體的數據類型。當變量類型不確定時,awk默認其為字符串類型。這里有一個技巧:如果你要讓你的awk程序知道你所使用的變量的明確類型,你應當在在程序中給它賦初值。
awk的記錄,字段與內置變量
1. 記錄與字段
在 awk中,缺省的情況下總是將文本文件中的一行視為一個記錄,而將一行中的某一部分作為記錄中的一個字段。為了操作這些不同的字段,awk借用shell 的方法,用$1,$2,$3...這樣的方式來順序地表示行(記錄)中的不同字段。特殊地,awk用$0表示整個行(記錄)。不同的字段之間是用稱作分隔 符的字符分隔開的。系統默認的分隔符是空格。awk允許在命令行中用-F re的形式來改變這個分隔符。事實上,awk用一個內置的變量FS來記憶這個分隔符
? 2. 內置變量
awk中有好幾個這樣的內置變量,例如,記錄分隔符變量RS、當前工作的記錄數NR等等。
? 示例:顯示文件本文件testAwk中第3行到第6行,以字符%分隔的第一個字段,第三個字段:
awk -F % 'NR==3,NR==6 {printf $1? $3}' testAwk
???
? 示例:殺死系統中所有top進程
????ps -ef|grep " top" |grep -v "grep"|awk '{printf $2}'|xargs kill -9
??? 或
????kill -9 `ps -ef|grep " top" |grep -v "grep"|awk '{printf $2}'`
awk內置變量
awk有許多內置變量用來設置環境信息,這些變量可以被改變,下面給出了最常用的一些變量。
此外,$0變量是指整條記錄。$1表示當前行的第一個域,$2表示當前行的第二個域,......以此類推。
統計/etc/passwd:文件名,每行的行號,每行的列數,對應的完整行內容:
使用printf替代print,可以讓代碼更加簡潔,易讀
print 和 printf
awk中同時提供了print和printf兩種打印輸出的函數。
其中print函數的參數可以是變量、數值或者字符串。字符串必須用雙引號引用,參數用逗號分隔。
如果沒有逗號,參數就串聯在一起而無法區分。這里,逗號的作用與輸出文件的分隔符的作用是一樣的,只是后者是空格而已。
printf函數,其用法和C語言中printf基本相似,可以格式化字符串,輸出復雜時,printf更加好用,代碼更易懂。
格式化字符串輸出(sprintf使用):
其中格式化字符串包括兩部分內容: 一部分是正常字符, 這些字符將按原樣輸出; 另一部分是格式化規定字符, 以"%"開始, 后跟一個或幾個規定字符,用來確定輸出內容格式。
| 格式符 | 說明 |
| %d | 十進制有符號整數 |
| %u | 十進制無符號整數 |
| %f | 浮點數 |
| %s | 字符串 |
| %c | 單個字符 |
| %p | 指針的值 |
| %e | 指數形式的浮點數 |
| %x | %X 無符號以十六進制表示的整數 |
| %o | 無符號以八進制表示的整數 |
| %g | 自動選擇合適的表示法 |
print & $0
-f 指定腳本文件
-F 指定分隔符
// 匹配代碼塊
IF 語句
統計某個文件夾下的文件占用的字節數,過濾4096大小的文件(一般都是文件夾):
循環語句(while,for,do)
awk的循環基本結構
有了這些語句,其實很多shell程序都可以交給awk,而且性能是非常快的。
break 當 break 語句用于 while 或 for 語句時,導致退出程序循環。
continue 當 continue 語句用于 while 或 for 語句時,使程序循環移動到下一個迭代。
next 能能夠導致讀入下一個輸入行,并返回到腳本的頂部。這可以避免對當前輸入行執行其他的操作過程。
exit 語句使主輸入循環退出并將控制轉移到END,如果END存在的話。如果沒有定義END規則,或在END中應用exit語句,則終止腳本的執行。
條件表達式
邏輯運算符
數值運算
輸出分隔符OFS
輸出處理結果到文件
數組
因為awk中數組的下標可以是數字和字母,數組的下標通常被稱為關鍵字(key)。值和關鍵字都存儲在內部的一張針對key/value應用hash的表格里。由于hash不是順序存儲,因此在顯示數組內容時會發現,它們并不是按照你預料的順序顯示出來的。數組和變量一樣,都是在使用時自動創建的,awk也同樣會自動判斷其存儲的是數字還是字符串。一般而言,awk中的數組用來從記錄中收集信息,可以用于計算總和、統計單詞以及跟蹤模板被匹配的次數等等。
netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}' netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}' 9523 1 9929 1 LISTEN 6 7903 1 3038/cupsd 1 7913 1 10837 1 9833 1顯示/etc/passwd的賬戶
其他awk用法
awk腳本
awk腳本可以由一條或多條awk_cmd組成,對于多個awk_cmd,一個awk_cmd完成后,應該另起一行,以便進行隔。? awk_cmd由兩部分組成:?awk_pattern { actions }。 另外,在awk命令中直接使用awk_script時,awk_script也可以被分成多行書寫,但必須確保整個awk_script被單引號括起來。 awk命令的一般形式: awk '?BEGIN?{ actions } awk_pattern1 { actions } ............ awk_patternN { actions } END?{ actions } ' inputfile 其中 BEGIN { actions } 和 END { actions } 是可選的。 在awk腳本中可以使用AWK本身內置變量,如下:? ARGC?命令行變元個數 ARGV?命令行變元數組 FILENAME?當前輸入文件名 FNR?當前文件中的記錄號 FS?輸入域分隔符,默認為一個空格 RS?輸入記錄分隔符 NF?當前記錄里域個數 NR?到目前為止記錄數 OFS?輸出域分隔符 ORS?輸出記錄分隔符AWK腳本的運行過程:
awk的流程控制
BEGIN和END:
任何在BEGIN之后列出的操作(在{}內)將在awk開始掃描輸入之前執行,而END之后列出的操作將在掃描完全部的輸入之后執行。因此,通常使用BEGIN來顯示變量和預置(初始化)變量,使用END來輸出最終結果。
例:累計銷售文件xs中的銷售金額(假設銷售金額在記錄的第三字段):
$awk
>'BEGIN { FS=":";print "統計銷售金額";total=0}
>{print $3;total=total+$3;}
>END {printf "銷售金額總計:%.2f",total}' sx
(注:>是shell提供的第二提示符,如要在shell程序awk語句和awk語言中換行,則需在行尾加反斜杠\)
在這里,BEGIN預置了內部變量FS(字段分隔符)和自定義變量total,同時在掃描之前顯示出輸出行頭。而END則在掃描完成后打印出總合計。
awk_pattern
awk_pattern模式部分決定actions動作部分何時觸發及觸發actions。
awk_pattern可以是以下幾種類型:
awk內置字符串函數: gsub(r,s) ??????????在整個$0中用s替代r awk 'gsub(/name/,"xingming") {print $0}' temp gsub(r,s,t) ????????在整個t中用s替代r index(s,t) ?????????返回s中字符串t的第一位置 awk 'BEGIN {print index("Sunny","ny")}' temp ????返回4 length(s) ??????????返回s的長度 match(s,r) ?????????測試s是否包含匹配r的字符串 awk '$1=="J.Lulu" {print match($1,"u")}' temp ???返回4 split(s,a,fs) ??????在fs上將s分成序列a awk 'BEGIN {print split("12#345#6789",myarray,"#")"' 返回3,同時myarray[1]="12", myarray[2]="345", myarray[3]="6789" sprint(fmt,exp) ????返回經fmt格式化后的exp sub(r,s) ??從$0中最左邊最長的子串中用s代替r(只更換第一遇到的匹配字符串) substr(s,p) ????????返回字符串s中從p開始的后綴部分 substr(s,p,n) ??????返回字符串s中從p開始長度為n的后綴部分 awk字符串連接操作?[chengmo@centos5 ~]$ awk 'BEGIN{a="a";b="b";c=(a""b);print c}' ?????
AWK 內置函數
awk內置函數,主要分以下3種類似:算數函數、字符串函數、其它一般函數、時間函數
1.以下示例了printf函數,它與C語言相似,如下,顯示testAwk文件中行號與第1個字段:$awk '{printf"%03d%s\n",NR,$1}' testAwk 2. 顯示文本文件mydoc匹配(含有)字符串"sun"的所有行$awk '/sun/{print}' mydoc 3.由于顯示整個記錄(全行)是awk的缺省動作,因此可以省略action項$awk '/sun/' mydoc 4.示第一個匹配Sun或sun的行與第一個匹配Moon或moon的行之間的行,并顯示到標準輸出上:$awk '/[Ss]un/,/[Mm]oon/ {print}' myfile 5.下面的示例顯示了內置變量和內置函數length()的使用:$awk 'length($0)>80 {print NR}' myfile 6.UNIX中的用戶進行安全性檢查。方法是考察/etc下的passwd文件,檢查其中的passwd字段(第二字段)是否為為"*"如不為"*",則表示該用戶沒有設置密碼,顯示出這些用戶名(第一字段)。#awk -F: '$2=="" {printf("%s no password!\n",$1' /etc/passwd在這個示例中,passwd文件的字段分隔符是“:”,因此,必須用-F:來更改默認的字段分隔符,這個示例中也涉及到了內置函數printf的使用一、算術函數:
以下算術函數執行與 C 語言中名稱相同的子例程相同的操作:
| 函數名 | 說明 |
| atan2( y, x ) | 返回 y/x 的反正切。 |
| cos( x ) | 返回 x 的余弦;x 是弧度。 |
| sin( x ) | 返回 x 的正弦;x 是弧度。 |
| exp( x ) | 返回 x 冪函數。 |
| log( x ) | 返回 x 的自然對數。 |
| sqrt( x ) | 返回 x 平方根。 |
| int( x ) | 返回 x 的截斷至整數的值。 |
| rand( ) | 返回任意數字 n,其中 0 <= n < 1。 |
| srand( [Expr] ) | 將 rand 函數的種子值設置為 Expr 參數的值,或如果省略 Expr 參數則使用某天的時間。返回先前的種子值。 |
二、字符串函數:
| 函數 | 說明 |
| gsub( Ere, Repl, [ In ] ) | 除了正則表達式所有具體值被替代這點,它和 sub 函數完全一樣地執行,。 |
| sub( Ere, Repl, [ In ] ) | 用 Repl 參數指定的字符串替換 In 參數指定的字符串中的由 Ere 參數指定的擴展正則表達式的第一個具體值。sub 函數返回替換的數量。出現在 Repl 參數指定的字符串中的 &(和符號)由 In 參數指定的與 Ere 參數的指定的擴展正則表達式匹配的字符串替換。如果未指定 In 參數,缺省值是整個記錄($0 記錄變量)。 |
| index( String1, String2 ) | 在由 String1 參數指定的字符串(其中有出現 String2 指定的參數)中,返回位置,從 1 開始編號。如果 String2 參數不在 String1 參數中出現,則返回 0(零)。 |
| length [(String)] | 返回 String 參數指定的字符串的長度(字符形式)。如果未給出 String 參數,則返回整個記錄的長度($0 記錄變量)。 |
| blength [(String)] | 返回 String 參數指定的字符串的長度(以字節為單位)。如果未給出 String 參數,則返回整個記錄的長度($0 記錄變量)。 |
| substr( String, M, [ N ] ) | 返回具有 N 參數指定的字符數量子串。子串從 String 參數指定的字符串取得,其字符以 M 參數指定的位置開始。M 參數指定為將 String 參數中的第一個字符作為編號 1。如果未指定 N 參數,則子串的長度將是 M 參數指定的位置到 String 參數的末尾 的長度。 |
| match( String, Ere ) | 在 String 參數指定的字符串(Ere 參數指定的擴展正則表達式出現在其中)中返回位置(字符形式),從 1 開始編號,或如果 Ere 參數不出現,則返回 0(零)。RSTART 特殊變量設置為返回值。RLENGTH 特殊變量設置為匹配的字符串的長度,或如果未找到任何匹配,則設置為 -1(負一)。 |
| split( String, A, [Ere] ) | 將 String 參數指定的參數分割為數組元素 A[1], A[2], . . ., A[n],并返回 n 變量的值。此分隔可以通過 Ere 參數指定的擴展正則表達式進行,或用當前字段分隔符(FS 特殊變量)來進行(如果沒有給出 Ere 參數)。除非上下文指明特定的元素還應具有一個數字值,否則 A 數組中的元素用字符串值來創建。 |
| tolower( String ) | 返回 String 參數指定的字符串,字符串中每個大寫字符將更改為小寫。大寫和小寫的映射由當前語言環境的 LC_CTYPE 范疇定義。 |
| toupper( String ) | 返回 String 參數指定的字符串,字符串中每個小寫字符將更改為大寫。大寫和小寫的映射由當前語言環境的 LC_CTYPE 范疇定義。 |
| sprintf(Format, Expr, Expr, . . . ) | 根據 Format 參數指定的?printf?子例程格式字符串來格式化 Expr 參數指定的表達式并返回最后生成的字符串。 |
Ere都可以是正則表達式
三、一般函數是:
| 函數 | 說明 |
| close( Expression ) | 用同一個帶字符串值的 Expression 參數來關閉由 print 或 printf 語句打開的或調用 getline 函數打開的文件或管道。如果文件或管道成功關閉,則返回 0;其它情況下返回非零值。如果打算寫一個文件,并稍后在同一個程序中讀取文件,則 close 語句是必需的。 |
| system(Command ) | 執行 Command 參數指定的命令,并返回退出狀態。等同于system?子例程。 |
| Expression | getline [ Variable ] | 從來自 Expression 參數指定的命令的輸出中通過管道傳送的流中讀取一個輸入記錄,并將該記錄的值指定給 Variable 參數指定的變量。如果當前未打開將 Expression 參數的值作為其命令名稱的流,則創建流。創建的流等同于調用?popen?子例程,此時 Command 參數取 Expression 參數的值且 Mode 參數設置為一個是 r 的值。只要流保留打開且 Expression 參數求得同一個字符串,則對 getline 函數的每次后續調用讀取另一個記錄。如果未指定 Variable 參數,則 $0 記錄變量和 NF 特殊變量設置為從流讀取的記錄。 |
| getline [ Variable ] < Expression | 從 Expression 參數指定的文件讀取輸入的下一個記錄,并將 Variable 參數指定的變量設置為該記錄的值。只要流保留打開且 Expression 參數對同一個字符串求值,則對 getline 函數的每次后續調用讀取另一個記錄。如果未指定 Variable 參數,則 $0 記錄變量和 NF 特殊變量設置為從流讀取的記錄。 |
| getline [ Variable ] | 將 Variable 參數指定的變量設置為從當前輸入文件讀取的下一個輸入記錄。如果未指定 Variable 參數,則 $0 記錄變量設置為該記錄的值,還將設置 NF、NR 和 FNR 特殊變量。 |
四、時間函數
| 函數名 | 說明 |
| mktime( YYYY MM DD HH MM SS[ DST]) | 生成時間格式 |
| strftime([format [, timestamp]]) | 格式化時間輸出,將時間戳轉為時間字符串? 具體格式,見下表. |
| systime() | 得到時間戳,返回從1970年1月1日開始到當前時間(不計閏年)的整秒數 |
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) |
| %% | 百分號(%) |
以上是awk常見 內置函數使用及說明,希望對大家有所幫助。
awk中的自定義函數
原始的awk并不提供函數功能,只有在nawk或較新的awk版本中才可以增加函數
awk函數的定義方法如下:
? ? ? ? 在gawk中允許將function省略為func,但其它版本的awk不允許。在 awk中調用函數比較簡單,其方法與C語言相似,但awk比C語言更為靈活,它不執行參數有效性檢查。換句話說,在你調用函數時,可以列出比函數預計(函 數定義中規定)的多或少的參數,多余的參數會被awk所忽略,而不足的參數,awk將它們置為缺省值0或空字符串,具體置為何值,將取決于參數的使用方 式。在函數中使用形如:return 返回值 格式的語句。
例: 下面的例子演示了函數的使用。在這個示例中,定義了一個名為print_header的函數,該函數調用了兩個參數FileName和 PageNum,FileName參數傳給函數當前使用的文件名,PageNum參數是當前頁的頁號。這個函數的功能是打印(顯示)出當前文件的文件名, 和當前頁的頁號。完成這個功能后,這個函數將返回下一頁的頁號。
QUOTE: nawk ‘{getline d; print d”#”$3}’ data.txt ?awk首先讀入第一行,接著處理getline函數,然后把下一行指定給變量d,再先打印d,由于d后面有換行符,所以后面緊跟的#會覆蓋d,后面的$3同樣也會覆蓋d。 QUOTE: nawk ‘{getline; print $0”#”$3}’ data.txt awk首先讀入第一行接著處理getline函數,然后把下一行指定給$0,現在的$0已經是下一行內容,后面的#和$3(從$0中取)會覆蓋$0的內容。 在awk中,有時需要調用系統工具來完成awk不擅長的工作,awk提供的system命令可以用來執行,但收不到外部工具的輸出結果。好在可以運用getline來滿足這個需求。例如 test.awk: { ???datecommand="/bin/date -j -f \"%d/%b/%Y:%H:%M:%S\" " $olddatestr " \"+%Y%m%d %H%M%S\""; ???datecommand | getline newdatestr? ???close(datecommand); } ? 外部命令需要awk占用一個文件描述符,而awk最多能打開的文件有一個上限,而且不大(比如說16),所以最后做一個close是好習慣。把命令串定義為一個變量也是為了close的時候方便
awk高級輸入輸出
1.讀取下一條記錄:?
? ? ? ? awk的next語句導致awk讀取下一個記錄并完成模式匹配,然后立即執行相應的操作。通常它用匹配的模式執行操作中的代碼。next導致這個記錄的任何額外匹配模式被忽略。?
2.簡單地讀取一條記錄?
? ? ? ? awk 的 getline語句用于簡單地讀取一條記錄。如果用戶有一個數據記錄類似兩個物理記錄,那么getline將尤其有用。它完成一般字段的分離(設置字段變 量$0 FNR NF NR)。如果成功則返回1,失敗則返回0(到達文件尾)。如果需簡單地讀取一個文件,則可以編寫以下代碼:?
例:示例getline的使用?
{while(getline==1)?
{?
#process the inputted fields?
}?
}?
也可以使getline保存輸入數據在一個字段中,而不是通過使用getline variable的形式處理一般字段。當使用這種方式時,NF被置成0,FNR和NR被增值。?
用 戶也可以使用getline<"filename"方式從一個給定的文件中輸入數據,而不是從命令行所列內容輸入數據。此時,getline將完成 一般字段分離(設置字段變量$0和NF)。如果文件不存在,返回-1,成功,返回1,返回0表示失敗。用戶可以從給定文件中讀取數據到一個變量中,也可以 用stdin(標準輸入設備)或一個包含這個文件名的變量代替filename。值得注意的是當使用這種方式時不修改FNR和NR。?
另一種使用getline語句的方法是從UNIX命令接受輸入,例如下面的例子:?
例:示例從UNIX命令接受輸入?
{while("who -u"|getline)?
{?
#process each line from the who command?
}?
}?
當然,也可以使用如下形式:?
"command" | getline variable?
3.關閉文件:?
? ? ? ? awk中允許在程序中關閉一個輸入或輸出文件,方法是使用awk的close語句。?
close("filename")?
filename可以是getline打開的文件(也可以是stdin,包含文件名的變量或者getline使用的確切命令)。或一個輸出文件(可以是stdout,包含文件名的變量或使用管道的確切命令)。?
4.輸出到一個文件:?
? ? ? ? awk中允許用如下方式將結果輸出到一個文件:?
printf("hello word!\n")>"datafile"?
或?
printf("hello word!\n")>>"datafile"?
5.輸出到一個命令?
? ? ? ? awk中允許用如下方式將結果輸出到一個命令:?
printf("hello word!\n")|"sort-t','"
awk與shell script混合編程
因 為awk可以作為一個shell命令使用,因此awk能與shell批處理程序很好的融合在一起,這給實現awk與shell程序的混合編程提供了可能。 實現混合編程的關鍵是awk與shell script之間的對話,換言之,就是awk與shell script之間的信息交流:awk從shell script中獲取所需的信息(通常是變量的值)、在awk中執行shell命令行、shell script將命令執行的結果送給awk處理以及shell script讀取awk的執行結果等等。?
1.awk讀取Shell script程序變量?
在awk中我們可以通過“'$變量名'”的方式讀取sell scrpit程序中的變量。?
例:在下面的示例中,我們將讀取sell scrpit程序中的變量Name,該變量存放的是文本myfile的撰寫者,awk將打印出這個人名。?
$cat writename?
:?
# @(#)?
#?
.?
.?
.?
Name="張三" nawk 'BEGIN {name="'Name'";\ printf("\t%s\t撰寫者%s\n",FILENAME,name");}\?
{...}END{...}' myfile?
.?
.?
.?
2.將shell命令的執行結果送給awk處理?
作為信息傳送的一種方法,我們可以將一條shell命令的結果通過管道線(|)傳遞給awk處理:?
例:示例awk處理shell命令的執行結果?
$who -u | awk '{printf("%s正在執行%s\n",$2,$1)}'?
該命令將打印出注冊終端正在執行的程序名。?
3.shell script程序讀awk的執行結果?
為 了實現shell script程序讀取awk執行的結果,我們可以采取一些特殊的方法,例如我們可以用變量名=`awk語句`的形式將awk執行的結果存放入一個 shell script變量。當然也可以用管道線的方法將awk執行結果傳遞給shell script程序處理。?
例:作為傳送消息 的機制之一,UNIX提供了一個向其所有用戶傳送消息的命令wall(意思是write to all寫給所有用戶),該命令允許向所有工作中的用戶(終端)發送消息。為此,我們可以通過一段shell批處理程序wall.shell來模擬這一程序 (事實上比較老的版本中wall就是一段shell批處理程序:?
$cat wall.shell?
:?
# @(#) wall.shell:發送消息給每個已注冊終端?
#?
cat >/tmp/
#用戶錄入消息文本 who -u | awk '{print $2}' | while read tty ?
do ?
cat /tmp/
>$tty?
done?
在 這個程序里,awk接受who -u命令的執行結果,該命令打印出所有已注冊終端的信息,其中第二個字段是已注冊終端的設備名,因此用awk命令析出該設備名,然后用while read tty語句循環讀出這些文件名到變量(shell script變量)tty中,作為信息傳送的終結地址。?
4.在awk中執行shell命令行----嵌入函數system()?
system()是一個不適合字符或數字類型的嵌入函數,該函數的功能是處理作為參數傳遞給它的字符串。system對這個參數的處理就是將其作為命令處理,也就是說將其當作命令行一樣加以執行。這使得用戶在自己的awk程序需要時可以靈活地執行命令或腳本。?
例:下面的程序將使用system嵌入函數打印用戶編制好的報表文件,這個文件存放在名為myreport.txt的文件中。為簡約起見,我們只列出了其END部分:?
.?
.?
.?
END {close("myreport.txt");system("lp myreport.txt");}?
在這個示例中,我們首先使用close語句關閉了文件myreport.txt文件,然后使用system嵌入函數將myreport.txt送入打印機打印。?
入門實例
假設last -n 5的輸出如下 [root@www ~]# last -n 5 <==僅取出前五行 root pts/1 192.168.1.100 Tue Feb 10 11:21 still logged in root pts/1 192.168.1.100 Tue Feb 10 00:46 - 02:28 (01:41) root pts/1 192.168.1.100 Mon Feb 9 11:41 - 18:30 (06:48) dmtsai pts/1 192.168.1.100 Mon Feb 9 11:41 - 11:41 (00:00) root tty1 Fri Sep 5 14:09 - 14:10 (00:01) 如果只是顯示最近登錄的5個帳號 #last -n 5 | awk '{print $1}' root root root dmtsai root awk工作流程是這樣的:讀入有'\n'換行符分割的一條記錄,然后將記錄按指定的域分隔符劃分域,填充域, $0則表示所有域,$1表示第一個域,$n表示第n個域。 默認域分隔符是"空白鍵" 或 "[tab]鍵",所以$1表示登錄用戶,$3表示登錄用戶ip,以此類推。 如果只是顯示/etc/passwd的賬戶#cat /etc/passwd |awk -F ':' '{print $1}' root daemon bin sys 這種是awk+action的示例,每行都會執行action{print $1}。 -F指定域分隔符為':'。 如果只是顯示/etc/passwd的賬戶和賬戶對應的shell,而賬戶與shell之間以tab鍵分割#cat /etc/passwd |awk -F ':' '{print $1"\t"$7}' root /bin/bash daemon /bin/sh bin /bin/sh sys /bin/s 如果只是顯示/etc/passwd的賬戶和賬戶對應的shell,而賬戶與shell之間以逗號分割, 而且在所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"。cat /etc/passwd |awk -F ':' 'BEGIN {print "name,shell"} {print $1","$7} END {print "blue,/bin/nosh"}' name,shell root,/bin/bash daemon,/bin/sh bin,/bin/sh sys,/bin/sh .... blue,/bin/nosh awk工作流程是這樣的: 先執行BEGING,然后讀取文件,讀入有/n換行符分割的一條記錄,然后將記錄按指定的域分隔符劃分域,填充域, $0則表示所有域,$1表示第一個域,$n表示第n個域,隨后開始執行模式所對應的動作action。 接著開始讀入第二條記錄······直到所有的記錄都讀完,最后執行END操作。搜索/etc/passwd有root關鍵字的所有行#awk -F: '/root/' /etc/passwd root:x:0:0:root:/root:/bin/bash 這種是pattern的使用示例,匹配了pattern(這里是root)的行才會執行action(沒有指定action,默認輸出每行的內容)。搜索支持正則,例如找root開頭的: awk -F: '/^root/' /etc/passwd 搜索/etc/passwd有root關鍵字的所有行,并顯示對應的shell # awk -F: '/root/{print $7}' /etc/passwd /bin/bash 這里指定了action{print $7} 應用1 awk -F: '{print NF}' helloworld.sh //輸出文件每行有多少字段 awk -F: '{print $1,$2,$3,$4,$5}' helloworld.sh //輸出前5個字段 awk -F: '{print $1,$2,$3,$4,$5}' OFS='\t' helloworld.sh //輸出前5個字段并使用制表符分隔輸出 awk -F: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh //制表符分隔輸出前5個字段,并打印行號 應用2 awk -F'[:#]' '{print NF}' helloworld.sh //指定多個分隔符: #,輸出每行多少字段 awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh //制表符分隔輸出多字段 應用3 awk -F'[:#/]' '{print NF}' helloworld.sh //指定三個分隔符,并輸出每行字段數 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh //制表符分隔輸出多字段 應用4 計算/home目錄下,普通文件的大小,使用KB作為單位 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}' ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}' //int是取整的意思 應用5 統計netstat -anp 狀態為LISTEN和CONNECT的連接數量分別是多少 netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}' 應用6 統計/home目錄下不同用戶的普通文件的總數是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}' mysql 199 root 374 統計/home目錄下不同用戶的普通文件的大小總size是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}' 應用7 輸出成績表 awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno. Name No. Math English Computer Total\n";printf "------------------------------------------------------------\n"}{math+=$3; eng+=$4; com+=$5;printf "%-8s %-7s %-7s %-7s %-9s %-10s %-7s \n",NR,$1,$2,$3,$4,$5,$3+$4+$5} END{printf "------------------------------------------------------------\n";printf "%-24s %-7s %-9s %-20s \n","Total:",math,eng,com;printf "%-24s %-7s %-9s %-20s \n","Avg:",math/NR,eng/NR,com/NR}' test0 [root@localhost home]# cat test0 Marry 2143 78 84 77 Jack 2321 66 78 45 Tom 2122 48 77 71 Mike 2537 87 97 95 Bob 2415 40 57 62附錄:?
1.awk的常規表達式元字符?
\ 換碼序列?
^ 在字符串的開頭開始匹配?
$ 在字符串的結尾開始匹配?
. 與任何單個字符串匹配?
[ABC] 與[]內的任一字符匹配?
[A-Ca-c] 與A-C及a-c范圍內的字符匹配(按字母表順序)?
[^ABC] 與除[]內的所有字符以外的任一字符匹配?
Desk|Chair 與Desk和Chair中的任一個匹配?
[ABC][DEF] 關聯。與A、B、C中的任一字符匹配,且其后要跟D、E、F中的任一個字符。?
* 與A、B或C中任一個出現0次或多次的字符相匹配?
+ 與A、B或C中任何一個出現1次或多次的字符相匹配?
? 與一個空串或A、B或C在任何一個字符相匹配?
(Blue|Black)berry 合并常規表達式,與Blueberry或Blackberry相匹配?
2.awk算術運算符?
運算符 用途?
------------------?
x^y x的y次冪?
x**y 同上?
x%y 計算x/y的余數(求模)?
x+y x加y?
x-y x減y?
x*y x乘y?
x/y x除y?
-y 負y(y的開關符號);也稱一目減?
++y y加1后使用y(前置加)?
y++ 使用y值后加1(后綴加)?
--y y減1后使用y(前置減)?
y-- 使用后y減1(后綴減)?
x=y 將y的值賦給x?
x+=y 將x+y的值賦給x?
x-=y 將x-y的值賦給x?
x*=y 將x*y的值賦給x?
x/=y 將x/y的值賦給x x%=y 將x%y的值賦給x?
x^=y 將x^y的值賦給x?
x**=y 將x**y的值賦給x?
3.awk允許的測試:?
操作符 含義?
x==y x等于y?
x!=y x不等于y?
x>y x大于y?
x>=y x大于或等于y?
x<y x小于y?
x<=y x小于或等于y??
x~re x匹配正則表達式re??
x!~re x不匹配正則表達式re??
4.awk的操作符(按優先級升序排列)?
= 、+=、 -=、 *= 、/= 、 %=?
||?
&&?
> >= < <= == != ~ !~?
xy (字符串連結,'x''y'變成"xy")?
+ -?
* / %?
++ --?
5.awk內置變量(預定義變量)?
說明:表中v項表示第一個支持變量的工具(下同):A=awk,N=nawk,P=POSIX awk,G=gawk?
V 變量 含義 缺省值?
--------------------------------------------------------?
N ARGC 命令行參數個數?
G ARGIND 當前被處理文件的ARGV標志符?
N ARGV 命令行參數數組?
G CONVFMT 數字轉換格式 %.6g?
P ENVIRON UNIX環境變量?
N ERRNO UNIX系統錯誤消息?
G FIELDWIDTHS 輸入字段寬度的空白分隔字符串?
A FILENAME 當前輸入文件的名字?
P FNR 當前記錄數?
A FS 輸入字段分隔符 空格?
G IGNORECASE 控制大小寫敏感0(大小寫敏感)?
A NF 當前記錄中的字段個數?
A NR 已經讀出的記錄數?
A OFMT 數字的輸出格式 %.6g?
A OFS 輸出字段分隔符 空格?
A ORS 輸出的記錄分隔符 新行?
A RS 輸入的記錄他隔符 新行?
N RSTART 被匹配函數匹配的字符串首?
N RLENGTH 被匹配函數匹配的字符串長度?
N SUBSEP 下標分隔符 "\034"?
6.awk的內置函數?
V 函數 用途或返回值?
------------------------------------------------?
N gsub(reg,string,target) 每次常規表達式reg匹配時替換target中的string?
N index(search,string) 返回string中search串的位置?
A length(string) 求串string中的字符個數?
N match(string,reg) 返回常規表達式reg匹配的string中的位置?
N printf(format,variable) 格式化輸出,按format提供的格式輸出變量variable。?
N split(string,store,delim) 根據分界符delim,分解string為store的數組元素?
N sprintf(format,variable) 返回一個包含基于format的格式化數據,variables是要放到串中的數據?
G strftime(format,timestamp) 返回一個基于format的日期或者時間串,timestmp是systime()函數返回的時間?
N sub(reg,string,target) 第一次當常規表達式reg匹配,替換target串中的字符串?
A substr(string,position,len) 返回一個以position開始len個字符的子串?
P totower(string) 返回string中對應的小寫字符?
P toupper(string) 返回string中對應的大寫字符?
A atan(x,y) x的余切(弧度)?
N cos(x) x的余弦(弧度)?
A exp(x) e的x冪?
A int(x) x的整數部分?
A log(x) x的自然對數值?
N rand() 0-1之間的隨機數?
N sin(x) x的正弦(弧度)?
A sqrt(x) x的平方根?
A srand(x) 初始化隨機數發生器。如果忽略x,則使用system()?
G system() 返回自1970年1月1日以來經過的時間(按秒計算)
總結
以上是生活随笔為你收集整理的linux命令终极系列awk的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 复制带随机节点的链表
- 下一篇: linux 之间 copy 传输文件方法