awk是linux環境下的一個命令行工具,可是因爲awk強大的能力,咱們能夠爲awk工具傳遞一個字符串,該字符串的內容相似一種編程語言的語法,咱們能夠稱其爲Awk語言,而awk工具自己則能夠看做是Awk語言的解析器。就比如python解析器與Python語言的關係。咱們通常使用awk來作什麼,awk又適合作什麼工做呢。因爲awk天生提供對文件中文本分列進行處理,因此若是一個文件中的每行都被特定的分隔符(常見的是空格)隔開,咱們能夠將這個文件當作是由不少列的文本組成,這樣的文件最適合用awk進行處理,其實awk在工做中不少時候被用來處理log文件,進行一些統計工做等。html
awk最經常使用的工做通常是遍歷一個文件中的每一行,而後分別對文件的每一行進行處理,一個完整的awk命令形式以下:python
awk [options] 'BEGIN{ commands } pattern{ commands } END{ commands }' file
linux
其中options表示awk的可選的命令行選項,其中最經常使用的恐怕是 -F 它指定將文件中每一行分隔成列的分隔符號。而緊接着後面的單引號裏面的全部內容是awk的程序腳本,awk須要對文件每一行分割後的每一列作處理。file則是awk要處理的文件名稱。讓咱們經過demo來體會awk的功能。正則表達式
echo '11 22 33 44' | awk '{print $3" "$2" "$1}'
輸出:33 22 11shell
咱們將字符串 11 22 33 44 經過管道傳遞給awk命令,至關於awk處理一個文件,該文件的內容就是 11 22 33 44 上面的命令中咱們並無添加 -F 指定分割符號,實際上默認狀況下awk使用空格分割每一行,若是須要指定別的字符則使用-F顯示指定。上面的命令是將 11 22 33 44 經過空格(無論列之間有多少個空格都將看成一個空格處理)分割成4列,在awk中有一種經過 $數字
引用的變量,這種變量引用的內容就是當前行中分割的每一列的內容,數字的序號從1開始,例如$1表示第1列的內容,$2表示第二列,以此類推。$0 表示當前整行的內容。print是awk的內置函數,用於打印出變量的值。 而咱們在$3 $2 $1 之間添加了用雙引號引發來的空格,若是沒有,則這些變量的值打印出來會連在一塊兒。這裏的awk命令中{}裏面的內容其實是咱們上面完整模式的中間部分,咱們省略了上面的BEGIN塊,END塊,而且中間的程序塊咱們也省略掉了pattern部分,也就是若是不添加BEGIN或者END說明那麼該程序塊就是上面完整模式中的中間的那個程序塊,該中間的程序塊所執行的操做就是循環處理文件內容的每一行,若是文件有10行,那麼中間的程序塊要運行10次,每一次處理一行的內容,而且處理完當前行以後,下次循環會自動依次處理接下來的行內容。
咱們來看看,若是有兩列是什麼效果呢,例如:
echo -e '11 22 33 44\naa bb cc dd' | awk '{print $3" "$2" "$1}'
輸出:
33 22 11
cc bb aa
注意這裏echo命令使用了-e選項的目的就是爲了保持字符串中的\n的格式可以生效,不然該換行將被忽略。那麼上面的命令是如何執行的呢,咱們模擬一下awk的執行過程,首先awk讀取第一行的內容,使用空格分隔該行中的列,並將字符串11賦值給$1,22賦值給$2,33賦值給$3,44賦值給$4。而後經過print打印出來。接着讀取第二行的內容,一樣執行上面的操做。編程
咱們已經學習了awk最簡單的命令,下面咱們再加一點東西進去,在程序塊的前面添加pattern部分,例如:
echo -e '1 2 3 4\n5 6 7 8' | awk '$1>2{print $3" "$2" "$1}'
輸出:7 6 5
該程序與上面的程序幾乎同樣,只不過咱們在程序塊前面添加了 $1>2 表示若是當前行的第1列的值大於2則處理當前行,不然不處理。說白了pattern部分是用來從文件中篩選出須要處理的行進行處理的,若是沒有則循環處理文件中的全部行。pattern部分能夠是任何條件表達式的判斷結果,例如>,<,==,>=,<=,!= 同時還可使用+,-,*,/運算與條件表達式相結合的複合表達式,邏輯 &&,||,! 一樣也可使用進來。另外pattern部分還可使用 /正則/ 選擇須要處理的行。數組
BEGIN語句塊是在匹配文件第一行以前運行的語句塊。因爲是匹配第一行以前運行,實際上在BEGIN語句塊中 $n 是不可用的。通常狀況下能夠在BEGIN語句塊中作一些變量(awk中能夠自定義變量,直接爲一個變量賦值就定義了一個變量,awk中沒有專門定義變量的關鍵字)初始化的工做,以及一些只須要在開始僅打印一次的輸出信息(例如輸出表的表頭)。例如:
echo -e '1 2 3 4\n5 6 7 8' | awk 'BEGIN{print "c1 c2 c3";print ""}{print $3" "$2" "$1}'
輸出爲:
c1 c2 c3
3 2 1
7 6 5
注意一個語句塊(花括號包圍)中能夠有多條語句,使用分號隔開,這與C語言同樣。若是須要單獨打印空行,須要使用 print "" 咱們上面就實現了輸出表頭的效果。bash
END語句塊是在awk循環執行完全部行的處理以後,才執行的,與BEGIN同樣,END語句塊也只執行一次,咱們看看完整的例子。
echo -e '1\n2\n3' | awk 'BEGIN{print "begin"}{print $1}END{print "end"}'
輸出:
begin
1
2
3
end編程語言
test.txt 的內容以下:
11 22 33
23 45 34
22 32 43
awk 'BEGIN{sum=0}{sum+=$1}END{print sum}' test.txt
輸出結果:56
首先在BEGIN語句塊中爲變量sum賦值0,而後在循環語句塊中將每一行的第1列加到sum中,當文件的全部行所有循環處理完成以後,打印出sum變量的值。固然這個例子中BEGIN語句塊是能夠省略的,咱們能夠直接在循環語句塊中使用sum變量,此時sum第一次使用,該變量會自動被創建,默認的初始值是0。函數
awk的全部語句塊中均可以使用判斷語句,其判斷語句語法與C語言同樣。
//test.txt內容以下
1 2 3
4 5 6
7 8 9
10 11 12
awk '{if($1%2==0)print $1" "$2" "$3}' test.txt
輸出:
4 5 6
10 11 12
//while循環
awk 'BEGIN{count=0;while(count<5){print count;count ++;}}'
輸出:
0
1
2
3
4
能夠看出awk的一個語句塊中能夠有比較複雜的複合語句,其使用與C語言幾乎差很少,多條語句之間用分號隔開,複合語句塊用花括號括起來作分隔。
//do..while循環
awk 'BEGIN{count=0;do{print count;count++}while(count<5)}'
輸出:
0
1
2
3
4
//for 循環
awk 'BEGIN{for(count=0;count<5;count++)print count}'
輸出:與上面同樣
能夠看到這幾種循環的形式與C語言是同樣的,對於咱們理解沒有任何障礙。awk中也使用break退出循環,使用continue跳過本次循環,其含義與C語言同樣。
awk中的數組基本上能夠看做是字典,看下面的例子:
//test.txt的文件內容
zhangsan 2 3
lisi 5 6
zhangsan 8 9
lisi 11 12
wangwu 33 11
將全部第一列相同的分紅一個組,並將該組中的第二列求和。
awk '{sum[$1]+=$2}END{for(k in sum)print k" "sum[k]}' test.txt
輸出:
zhangsan 10
lisi 16
wangwu 33
這個例子裏面使用了for..in循環來遍歷數組的key,同時經過key來獲得數組的值。對於key不是數字的數組,是不能經過普通的for循環來以數字索引訪問數組元素的。咱們能夠經過length()函數來得到數組的元素個數,例如length(array)
有的時候咱們在shell中計算出來的變量值須要被awk命令使用,咱們固然不能在awk中直接使用 $VAR,由於美圓符號在awk中原本就是特殊符號,在awk中可使用 $n 引用當前行的第n列的值,因此直接這麼使用是不行的,awk提供了一個選項 -v 來指定變量,在awk中有兩種變量,一種是 $n 形式的變量,這個是在循環文件的行的時候,用來引用當前行的第n列的值,還有一種變量,不用定義能夠直接使用,不須要用美圓符號來引用。下面看看shell中的變量值如何在awk中使用:
a=22 b=33 awk -v x=$a -v y=$b 'BEGIN{print x" "y}'
能夠看到咱們只須要在使用awk的時候經過 -v 指定awk中將會用到的變量便可,而變量值則能夠經過引用shell變量獲得,也就是說咱們只能在awk的options部分引用shell的變量,在awk的語句塊中使用美圓符號引用變量會被awk解析成本身的變量而不是shell的變量。
awk定義了不少內置函數,下面咱們根據函數類型列出經常使用的函數,下面的函數只是一部分,完整的函數列表則須要查閱awk的官方文檔。
算術:
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(reg,str1,str2) 使用str1替換全部str2中符合正則表達式reg的子串
sub(reg,str1,str2) 含義與gsub相同,只不過gsub是替換全部匹配,sub只替換第一個匹配
index(str,substr) 返回substr在str中第一次出現的索引,注意索引從1開始計算,若是沒有則返回0
length(str) 返回str字符串的長度,length函數還能夠返回數組元素的個數
blength(str) 返回字符串的字節數
match(str,reg) 與index函數同樣,只不過reg使用正則表達式,例如match("hello",/lo/)
split(str,array,reg)將str分隔成數組保存到array中,分隔使用正則reg,或者字符串均可以,返回數組長度
tolower(str) 轉換爲小寫
toupper(str) 轉換爲大寫
substr(str,start,length) 截取字符串,從start索引開始的length個字符,如不指定length則截取到末尾,索引從1開始
其餘:
system(command) 執行系統命令,返回退出碼
mktime( YYYY MM dd HH MM ss[ DST]) 生成時間格式
strftime(format,timestamp) 格式化時間輸出,將時間戳轉換爲時間字符串
systime() 獲得時間戳,返回從1970年1月1日開始到當前時間(不計閏年)的整秒數
awk中一樣定義了不少內置變量,咱們能夠直接像使用普通變量同樣使用他們,因爲awk的版本衆多,有些內置變量並非獲得全部awk版本的支持。
說明:[A][N][P][G]表示支持該變量的工具,[A]=awk、[N]=nawk、[P]=POSIXawk、[G]=gawk
$n 當前記錄的第n個字段,好比n爲1表示第一個字段,n爲2表示第二個字段。
$0 這個變量包含執行過程當中當前行的文本內容。
[N] ARGC 命令行參數的數目。
[G] ARGIND 命令行中當前文件的位置(從0開始算)。
[N] ARGV 包含命令行參數的數組。
[G] CONVFMT 數字轉換格式(默認值爲%.6g)。
[P] ENVIRON 環境變量關聯數組。
[N] ERRNO 最後一個系統錯誤的描述。
[G] FIELDWIDTHS 字段寬度列表(用空格鍵分隔)。
[A] FILENAME 當前輸入文件的名。
[P] FNR 同NR,但相對於當前文件。
[A] FS 字段分隔符(默認是任何空格)。
[G] IGNORECASE 若是爲真,則進行忽略大小寫的匹配。
[A] NF 表示字段數,在執行過程當中對應於當前的字段數。
[A] NR 表示記錄數,在執行過程當中對應於當前的行號。
[A] OFMT 數字的輸出格式(默認值是%.6g)。
[A] OFS 輸出字段分隔符(默認值是一個空格)。
[A] ORS 輸出記錄分隔符(默認值是一個換行符)。
[A] RS 記錄分隔符(默認是一個換行符)。
[N] RSTART 由match函數所匹配的字符串的第一個位置。
[N] RLENGTH 由match函數所匹配的字符串的長度。
[N] SUBSEP 數組下標分隔符(默認值是34)。
awk官方文檔:
https://www.gnu.org/software/gawk/manual/gawk.html
您若是以爲寫的還不錯,給個讚唄