上一篇總結了下sed的用法,這一篇玩玩sed的好×××awk,學完它倆,以後就再也不用怕處理文本文件了。
awk其實和sed處理過程差不多,都是面向字符流的。sed和awk都相當於是一個加工廠,輸入的文本行,相當於原材料,原材料在工廠中經過一系列處理。然後輸出成品。
awk和sed不同的是,awk更加的強大了,基本上可以說大多數sed能夠實現的功能,awk都可以實現。。。。
但是實現相同的功能,大多情況下sed的過程更加的簡潔吧。
當然awk還有着更多的功能,awk本身就是一門類C的語言了,有變量,有流程控制,有函數。可以針對單行,多行,字段等進行更多的處理。
OK,先說說awk的架構吧
架構
awk腳本,可以說由三個例程組成。
例程長什麼樣的呢?
長這樣的:模式{}
模式用於匹配,{}裏面的東西,是對匹配成功的東西,處理的過程
OK,看看是哪三個吧?
awk 'BEGIN{} /正則/{} END{}' file
當然這三類例程,每類例程都是可選的,可以不出現,出現一次,或多次都可以。
BEGIN{}:BEGIN規則相關的例程,處理輸入前將做的處理。 這個例程是不讀取文件輸入行的,從上面 的圖中可以看到
/正則/{}:主輸入循環例程,處理輸入過程中將做的處理。這個例程其實就是awk爲我們封裝好的一個循環框架,循環變量是滿足匹配模式的行,循環終止條件是所有匹配的行都處理完了。所以循環的次數和匹配的行數相同,無輸入或無匹配的行,循環將不執行。。如果沒有/正則/這種模式匹配,則所有輸入行都執行循環
END{}:END規則相關的例程,處理輸入後將做的處理。這個例程主要做些掃尾的工作,比如主輸入循環中的最後的結果,在END{}中輸出
畫個圖,看一下三個例程的執行過程。
OK,我們再看看三個例程的變量,是怎麼用的
看到了吧,這三個小例子說明了,
1.前面例程定義的變量,在該例程執行完畢後,變量並不會消失,而是可以被後續的例程繼續使用。
2.後面例程定義的變量,前面的例程卻不可以使用的。這個想想也就明白了,你前面的例程都執行完畢了,我後面的變量還沒定義呢,你怎麼能使用我的變量呢?
模式匹配
可以是以下幾種方式
/regular expression/
relational expression
BEGIN
END
pattern,pattern
1.正則表達式使用元字符的擴展集,並且必須用//斜槓包圍,
2.關係表達式使用關係操作符
root@salt-master:~/sedAawk/awk# awk 'NF>2?/^an/:/^pu/' test ansible a one of its most powerful tools puppet?
3.BEGIN模式在第一個輸入行被讀取前使用,END模式在最後一個輸入行被讀取之後應用
4.使用!可以否定匹配,也就是處理和模式不匹配的行
root@salt-master:~/sedAawk/awk# awk '!NF>2?/^an/:/^pu/{print}' test puppet?
5.可以訪問若干行,和sed中一樣。pattern1,pattern2
root@salt-master:~/sedAawk/awk# awk '/^an/,/pu/' test ansible a one of its most powerful tools salt-stack also puppet? root@salt-master:~/sedAawk/awk# awk 'NR==1,NR==2' test ansible a one of its most powerful tools salt-stack also
6.除了BEGIN和END模式,都可以使用&&,||
root@salt-master:~/sedAawk/awk# awk '/^an/||/pu/' test ansible a one of its most powerful tools puppet?
7.可以將模式放在圓括號裏,確保正確的求值
root@salt-master:~/sedAawk/awk# awk '(/^an/||/pu/)' test ansible a one of its most powerful tools puppet? root@salt-master:~/sedAawk/awk# awk '!(/^an/||/pu/)' test salt-stack also chef? I do not know root@salt-master:~/sedAawk/awk# awk '!/^an/||/pu/' test salt-stack also puppet? chef? I do not know
8.BEGIN和END必須和操作相聯繫,如果編寫了多個BEGIN或END規則,它們在應用前被合成一個規則
記錄和字段
說到底awk主要還是要用來處理文本文件,我們最應該關注的還是主輸入循環例程,而BEGIN和END,則可以讓我們的處理過程更加的靈活強大
OK,來看看什麼是記錄和字段吧
記錄:就是我們輸入文本的每一行,就叫做一條記錄。在awk中可以用$0這個變量表示
字段:就是我們每條記錄按照特定的分隔符去分割,分割後每個小片段就是一個字段,用$1,$2,...表示
OK,說到字段,字段的劃分是繞不過的一個話題。
看一下,怎麼選定分隔符去劃分字段吧,一共有兩種方法去劃分字段。
第一種方法使用-F參數,舉個小例子
分割符可以用圖中的幾種方式去表示
默認情況下爲空格或製表符
可以指定分割符爲某一字符,加在-F參數的後面,可以緊挨着-F,用''或""括起來
可以用正則表達式來,表示分隔符
可以指定多個分割符
第二種方法,使用awk提供的一個系統變量FS,翻譯成英文是field segmentation,意思就是字段分割
OK,看一下怎麼用
使用FS這個系統變量指定分割符的時候,分隔符的形式和-F參數的那四種形式是一樣的。。。
不過我們一般把FS變量,定義在BEGIN例程中,當然也可以在命令行的-v參數後面。
注意:我們上面講的字段分割,如果在記錄的最開頭和最結尾出現分割符,會被awk忽略的
說完了記錄和字段,輸入這一塊就差不多了,記錄輸入之後,就是處理的過程了。這也是主輸入循環例程,主要乾的活
主輸入循環的處理過程,主要由語句,函數和表達式組成的了
表達式
表達式可以用來存儲,操作和檢索數據。一個表達式,通過計算一個返回值。
表達式由數字,字符串常量,變量,操作符,函數和正則表達式組成。
這裏先主要說說,常量,變量,操作符。。函數下一篇說
常量
awk中的常量有兩種,一個數字,二是字符串。一般用''或者""括起來,
注意:命令行上使用字符串,要用"",避免shell的影響
字符串中,可以使用轉義字符
\a,\b,\f,\n,\r,\t,\v,\ddd,\xbex,\c
變量
awk的變量和別的語言的變量有些不同。
1.awk的每個變量都有,字符串型值和數字型值。awk能夠根據表達式的前後關係,來自動的選取合適的值。
2.變量不必初始化,awk會自動把它們初始化爲空字符串,如果作爲數字,值則爲0
如awk 'BEGIN{print a}' ,結果爲空
操作符
算術操作符
+,-,*,/,%,^(取冪)
賦值運算符
++,--,+=,-=,*=,/=,%=,^=
關係操作符和布爾操作符主要用於兩個表達式之間的比較
關係操作符
<,>,<=,>=,==,!=,~(匹配),!~(不匹配)
布爾操作符
||
&&
!
系統變量
變量名 | 用途 |
FS(Field segmentation)(可改變) | 域分隔符,默認爲空格或製表符,可自定義爲任意單個或多個字符,及正則表達式 |
OFS(output Field segmentation)(可改變) | 和FS等效的輸出域分隔符,默認爲空格 |
NF(Number Fields)(不要改變) | 當前輸入記錄的字段個數,最好不要人爲的去改變這個值 |
RS(Record segmentation)(可改變) | 記錄分隔符,默認爲一個換行符。在處理多行記錄的時候,我們可能會把RS的值,改變 |
ORS(output Record segmentation)(可改變) | 和RS對應的輸出記錄分隔符,它的默認值也是一個換行符 |
FILENAME(不要改變) | 輸入文件的名稱 |
NR(Number Record)(不要改變) | 當前輸入記錄的編號,可以跨越多個文件 |
FNR(File Numberr Record)(不要改變) | 當前文件記錄的編號,跨文件的話,會重新從0開始 |
ARGC(不要改變) | 命令行參數個數 |
ARGV(不要改變) | 命令行參數數組 |
OFMT | 控制數字到字符串轉換,這個適合樓主的環境(mawk),現在不適合gawk了。。。。gawk用CONVFMT |
ENVIRON | UNIX環境變量 |
ERRNO | UNIX系統錯誤消息 |
IGNORECASE | 如果爲真,則忽略大小寫的匹配 |
RSTART | 被匹配函數,匹配的字符串首 |
RLENGTH | 被匹配函數的字符串長度 |
SUBSEP | \034 |
這麼多系統變量,其實前10個會被經常用到。。。後面那幾個,咱們平時分析個日誌,基本上不會用到這些東西,在這裏mark下,就不細說了。
第一組:FS,OPF,NF 這三個變量,都是針對字段的,看個例子
第二組:RS,ORS,NR,FNR這四個變量,都是針對記錄的,看個例子
其它的都用處不大,就不細究了。
格式化打印
和c語言中的printf一樣。
print和printf相比有啥優點呢?
唯一的優點就是,print是自動換行的,而printf要自己加\n,參數才能換行
printf語法格式
printf (for mat-expression [,arguments])
printf格式說明符
c,d,i,e,E,f,g,G,O,s,u,x,X,%
最常用的就仨,%d(數字),%s(字符串),%f(浮點數)
寬度和精度
格式:%寬度.精度 格式說明符
舉個例子大夥就知道怎麼用了
命令行參數
兩種方法:
看個例子
注意:
當使用awk -v var=argument時候,變量首先就會被傳遞給BEGIN相關的例程
而使用awk '' var=argument的時候,變量在BEGIN例程中是不可用的。
這是爲什麼呢?
因爲後面傳遞過來的參數,就像文件一樣被處理,賦值操作直到主循環例程開始執行時,纔會發生。