awk命令詳解

 awk命令詳解

 

1.調用awk:
第一種方式:命令行方式
awk [-F field-separator] 'commands' input-file(s)
[-F域分隔符]是可選的,因爲awk使用空格作爲缺省的域分隔符,因此如果要瀏覽域間有空格的文本,不必指定這個選項,如果要瀏覽諸如passwd文件,此文件各域以冒號作爲分隔符,則必須指明-F選項,如:
awk -F: 'commands' input-file
第二種方式是將所有awk命令插入一個文件,並使awk程序可執行,然後用awk命令解釋器作爲腳本的首行,以便通過鍵入腳本名稱來調用它。
第三種方式是將所有的awk命令插入一個單獨文件,然後調用:
awk -f awk-scrīpt-file input-files(s)
-f選項指明在文件awk_scrīpt_file中的awk腳本,input_file(s)是使用awk進行瀏覽的文件名。

2.awk腳本
2.1 模式和動作
任何awk語句都由模式和動作組成。在一個awk腳本中可能有許多語句。模式部分決定動作語句何時觸發及觸發事件。處理即對數據進行的操作。如果省略模式部分,動作將時刻保持執行狀態。
模式可以是任何條件語句或複合語句或正則表達式。模式包括兩個特殊字段 BEGIN和END。使用BEGIN語句設置計數和打印頭。BEGIN語句使用在任何文本瀏覽動作之前,之後文本瀏覽動作依據輸入文本開始執行。END語句用來在awk完成文本瀏覽動作後打印輸出文本總數和結尾狀態標誌。
2.2 域和記錄
使用$1,$3表示參照第1和第3域,注意這裏用逗號做域分隔。如果希望打印一個有5個域的記錄的所有域,可使用$0,意即所有域。
爲打印一個域或所有域,使用print命令。這是一個awk動作
(1) 抽取域
(2) 保存awk輸出
$ awk '{print $0}' grade.txt > wow
使用這種方法,顯示屏上不會顯示輸出結果。直接輸出到文件。
使用tee命令,在輸出文件的同時,輸出到屏幕
$ awk '{print $0}' grade.txt | tee delete_me_and_die
(3) 使和標準輸入
使用awk腳本輸入文件格式:
● $ belts.awk grade_student.txt
● $ belts.awk < grade2.txt
● $ grade2.txt | belts.awk
(4) 打印所有記錄
$ awk '{print $0}' grade.txt
(5) 打印單獨記錄
$ awk '{print $1,$4}' grade.txt
(6) 打印報告頭
域間使用\t進行劃分。下劃線使用\n強迫啓動新行
$ awk 'BEGIN {print "Name Belt\n----------------------------------"} {print $1"\t"$4}' grade.txt
(7) 打印信息尾
使用END語句
$ awk 'BEGIN {print "Name\n---------"} {print $1} END {"end-of-report"}' grade.txt

2.5 條件操作符
(1) 匹配:
$ awk '{if ($4~/Brown/) print $0}' grade.txt
如果在文本中查詢字符串"Brown",使用/Brown/
$ awk '$0 ~ /Brown/' grade.txt
(2) 精確匹配
$ awk '$3 == "48" {print $0}' grade.txt
$ awk '{if ($3=="48") print $0}' grade.txt
(3) 不匹配
$ awk '$0 !~ /Brown/' grade.txt
$ awk '{if($4 !~ /Brown/) print $0' grade.txt
精確不匹配
$ awk '$4 != "Brwon-2" {print $0}' grade.txt
(4) 小於
$ awk '{if ($6 < $7) print $0 "$1 Try better at the next comp"}' grade.txt
(5) 小於等於
$ awk '{if ($6 <= $7) print $1}' grade.txt
(6) 大於
$ awk '{if ($6 > $7) print $1}' grade.txt
(7) 設置大小寫
$ awk '/[Gg]reen/' grade.txt
(8) 任意字符
抽取名字,其記錄第一域的第四個字符是a,使用句點.。表達式/^...a/意爲行首前三個字符任意,第四個是a,尖角符號代表行首。
$ awk '$1 ~/^...a/' grade.txt
(9) 或關係匹配
爲抽取級別爲yellow或brown的記錄,使用豎線符|。意爲匹配|兩邊模式之一。注意,使用豎線符時,語句必須用圓括號括起來。
$ awk '$0~/(Yellow|Brown)/' grade.txt
(10) 行首
$ awk '/^48/' input-file
(11) AND
&& 意味着兩邊匹配均爲真
$ awk '{if ($1 == "P.Bunny" && $4 == "Yellow") print $0}' grade.txt
(12) OR
$ awk '{if ($4 == "Yellow" || $4 ~ /Brown/) print $0}' grade.txt

2.6 awk內置變量
  最常用的一些變量
--------------------------------------------------------
 ARGC   命令行參數個數
 ARGV   命令行參數排列
 ENVIRON  支持隊列中系統環境變量的使用
 FILENAME  awk瀏覽的文件名
 FNR   瀏覽文件的記錄數
 FS   設置輸入域分隔符,等價於命令行-F選項
 NF   瀏覽記錄的域個數
 NR   已讀的記錄數
 OFS   輸出域分隔符
 ORS   輸出記錄分隔符
 RS   控制記錄分隔符
--------------------------------------------------------

2.7 NF、NR和FILENAME
NR代表記錄處數
$ awk 'END {print NR}' grade.txt
$ 5
打印所有學生的記錄,並帶有其記錄號,並在END部分打印輸入文件名
NF顯示一條記錄中有幾個域
$ awk '{print NF,NR,$0}END{print FILENAME}' grade.txt
在從文件中抽取信息時,先檢查文件中是否有記錄。使用AND實現
$ awk '{if (NR > 0 && $4~/Brown/) print $0}' grade.txt
NF的強大功能是將變量$PWD的返回值傳入awk並顯示其目錄。這裏需要指定域分隔符
$ pwd
/usr/local/etc
$ echo $PWD | awk -F/ '{print $NF}'
另一個例子是顯示文件名:
$ echo "/usr/local/etc/rc.sybase" | awk -F/ '{print $NF}'
rc.sybase

2.8 awk操作符
awk使用操作符,基本表達式可以劃分爲數字型、字符串型、變量型、域及數組元素,
-----------------------------------------------------
 = += *= /= %= ^= 賦值操作符
 ?    條件表達操作符
 || && !   並、與、非
 ~ !~    匹配操作符,包括匹配與不匹配
 < <= == != >>  關係操作符
 + - * / % ^   算術操作符
 ++ --    前綴和後綴
-----------------------------------------------------
(1)設置輸入域到域變量名
一般的變量名設置方式爲name = $n,這裏name爲調用的域變量名,n爲實際域號。
例如,設置學生域名爲name,級別域名爲belt,操作爲name = $1; belts = $4。注意分號,它分隔awk命令。
$ awk '{name = $1; belts = $4; if(belts ~/Yellow/) print name " is belt " belts}' grade.txt
$ P.Bunny is belt Yellow

(2) 域值比較操作
有兩種方式測試一數值域是否小於另一數值域
1)在BEGIN中給變量名賦值。
2)在關係操作中使用實際數值。
查詢所有比賽中得分在27點的學生
$ awk '{if ($6 < 27) print $0}' grade.txt
J.Lulu          06/99   48317   green   9       24      26
J.Troll         07/99   4842    Brown-3 12      26      26
使用BEGIN
$ awk 'BEGIN {BASELINE="27"} {if ($6 < BASELINE) print $0}' grade.txt

(3) 修改數值域取值
當在awk中修改任何域時,修改的只是緩存裏的awk複本。awk會在變量NR和NF變量中反映出修改痕跡。
$1=$1+5,會將域1數值加5,但要確保賦值域其子集爲數值型。
修改M.Tansley的目前級別分域,
awk '{if ($1 == "M.Tansley") $6=$6-1; print $1, $6, $7}' grade.txt

(4) 修改文本域
修改文本域即對其重新賦值。需要做的就是賦給一個新的字符串。
$ awk '{if ($1 == "J.Troll") ($1 = "J.L.Troll"); print $1}' grade.txt

(5) 只顯示修改記錄
在模式後面使用花括號將只打印修改部分。取得模式,再根據模式結果實施操作。
$ awk '{if ($1 == "J.Troll") {$1 = "J.L.Troll"; print $1}}' grade.txt

(6) 創建新的輸出域
如創建一個基於其他域的加法新域{$4 = $2 + $3},假定記錄包含3上域,則域4爲新建域。
在文件grade.txt中創建新域8保存域目前級別分與域域最高級別分的減法值。表達式爲'{$8 = $7 - $6}',語法首先測試域目前級別分小於域最高組別分。
$ awk 'BEGIN {print "Name\t Difference"} {if ($6 < $7) {$8 = $7 - $6; print$1, $8}}' grade.txt
可以創建新域,賦給更有意義的變量名
$ awk 'BEGIN {print "Name\t Difference"} {if ($6 < $7) {diff = $7 - $6; print$1, diff}}' grade.txt

(7) 增加列值
爲增加列數或進行運行結果統計,使用符號 +=。增加的結果賦給符號左邊變量值,增加到變量的域在符號右邊。例如將$1加入變量total,表達式爲total+=$1。
將所有學生的'目前級別分'加在一起,方法是tot+=$6,tot即爲awk瀏覽的整個文件的域6結果總和。
$ awk '{(tot+=$6)}; END {print "Club student total points : " tot}' grade.txt
Club student total points : 155

(8) 文件長度相加
在目錄中查看文件時,快速查看所有文件的長度及其總和,但要排除子目錄。使用ls -l,然後管道輸出到awk
$ ls -l | awk '/^[^d]/ {print $9"\t"$5} {tot+=$5} END {print "total KB : " tot}'
data.f    193
grade.txt       179
grepstring      7
local.cshrc     136
local.login     157
local.profile   174
results.txt     2129
wow       179
total KB : 4690

(9) 內置的字符串函數
   awk內置字符串函數
-----------------------------------------------------------
 gsub(r,s)   在整個$0中用s替代r
 gsub(r,s,t)  在整個t中用s替代r
 index(s,t)   返回s中字符串t的第一個位置
 length(s)   返回s長度
 match(s,r)   測試s是否包含匹配r的字符串
 split(s,a,fs)  在fs上將s分成序列a
 sprint(fmt,exp)  返回經fmt格式化後的exp
 sub(r,s)   用$0中最左邊最長的子串代替s
 substr(s,p)  返回字符串s中從p開始的後綴部分
 substr(s,p,n)  返回字符串s中從p開始長度爲n的後綴部分
-----------------------------------------------------------
■gsub:

■index:
$ awk 'BEGIN {print index("Bunny", "ny")}' grade.txt
4

■length:
$ awk '$1 == "J.Troll" {print length($1)" "$1}' grade.txt
7 J.Troll
$ awk 'BEGIN{print length("A FEW GOOD MEN")}'
14

■match:如果不存在,返回0

■split
返回字符串數組元素個數。
$ awk 'BEGIN {print split("123#456#678", myarray, "#")}'
3

■sub
使用sub發現並替換模式的第一次出現位置。字符串STR包含'poped popo pill',執行下列sub命令
sub(/op/, "op", STR)。結果 'pOPed pope pill'
$ awk '$1 == "L.Tansley" {print substr($1, 1, 5)}' grade.txt
L.Tan

■substr:
它按照起始位置及長度返回字符串的一部分。
$ awk '$1 == "L.Tansley" {print substr($1, 1, 5)}' grade.txt
L.Tan
substr的另一種形式是返回字符串後綴或指定位置後面的字符
$ awk '{print substr($1, 3)}' grade.txt
在BEGIN部分定義字符串,在END部分返回從第t個字符開始抽取的子串。
$ awk 'BEGIN {STR="A FEW GOOD MEN"} END {print substr(STR, 7)}' grade.txt
GOOD MEN

■從shell中向awk傳入字符串:
通過管道把字符串傳入awk
$ echo "Stand-by" | awk '{print length($0)}'
8
設置文件名爲一變量,管道輸出到awk,返回不帶擴展名的文件名
$ STR="mydoc.txt"
$ echo $STR | awk '{print substr($STR,1,5)}'
mydoc

(10)字符串屏蔽序列
使用字符串或正則表達式時,有時需要在輸出中加入一新行或查詢一元字符。
   awk中使用的屏蔽序列
------------------------------------------------------------
 \b 退格鍵   \t  tab鍵
 \f 走紙換頁  \ddd  八進制值
 \n 新行    \c  任意其他特殊字符,例如\\爲返斜線符號
 \r 回車鍵 
------------------------------------------------------------
打印May Day,中間夾tab鍵,後跟兩個新行,再打印May Day,這次使用八進制數
$ awk 'BEGIN{print "May\tDay\n\nMay\t\104\141\171"}'

(11) awk輸出函數printf
   awk printf修飾符
----------------------------------------------------------------
  -   左對齊
  Width   域的步長,用0表示0步長
  .prec   最大字符串長度,或小數點右邊的位數
----------------------------------------------------------------

   awk printf格式
-------------------------------------------------------------
  %c   ASCII字符
  %d   整數
  %e   浮點數,科學記數法
  %f   浮點數,例如(123.44)
  %g   awk決定使用哪種浮點數轉換e或者f
  %o   八進制數
  %s   字符串
  %x   十六進制數
--------------------------------------------------------------
■ 字符轉換
觀察ASCII碼中65的等價值。管道輸出65到awk。
$ echo "65" | awk '{printf "%c\n", $0}'
A
當然也可以按同樣方式使用awk得到同樣結果
$ awk 'BEGIN {printf "%c\n", 65}'
A
所有的字符轉換都一樣,下面的例子表示進行浮點數轉換後'999'的輸出結果。整數傳入後被加了小數點。
$ awk 'BEGIN {printf "%f\n", 999}'

■ 格式化輸出
打印所有的學生名字和序列號,要求名字左對齊,15個字符長度,後跟序列號。注意\n換行符放在最後一個指示符後面。輸出將自動分成兩列。
$ awk '{printf "%-15s %s\n", $1, $3}' grade.txt
M.Tansley       48311
J.Lulu          48317
P.Bunny         48
J.Troll         4842
L.Tansley       4712
加入文本註釋幫助理解報文含義。可在正文前嵌入頭信息。
$ awk 'BEGIN {print "Name \t\tS.Number"} {printf "%-15s %s\n", $1, $3}' grade.txt
Name            S.Number
M.Tansley       48311
J.Lulu          48317
P.Bunny         48
J.Troll         4842
L.Tansley       4712

■ 向一行awk命令傳值
在查看awk腳本前,先來查看怎樣在awk命令行中傳遞變量。
awk執行前將值傳入awk變量,需要將變量放在命令行中,格式如下:
awk 命令變量 = 輸入文件值
在命令行中設置變量AGE等於10,然後傳入awk中,查詢年齡在10歲以下的所有學生
$ awk '{if ($5 < AGE) print $0}' AGE=10 grade.txt
要快速查看文件系統空間容量,觀察其是否達到一定水平。
$ df -k | awk '($4 ~/^[0-9]/) {if ($4 < TRIGGER) print $6"\t"$4}' TRIGGER=56000
使用who命令,who命令第一列包含註冊用戶名。
# who | awk '{print $1 " is logged on"}'
root is logged on
root is logged on
sun is logged on
awk傳入環境變量。使用環境變量LOGNAME支持當前用戶名。
# who | awk '{if ($1 == user) print $1 " you are connected to" $2}' user=$LOGNAME
root you are connected toconsole
root you are connected topts/4

 

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