awk 是 Linux/UNIX 下的用來操縱數據和產生報告的程序語言。 Nawk 是新的版本, gawk
是 Gnu 版本。awk 可用於命令行的簡單操做,也能夠寫入大的應用程序。由於 awk 能夠操縱數據,因此它是 Shell腳本和管理小型數據庫中必需的工具。linux
awk 執行過程分爲三個階段:讀輸入文件以前執行的代碼段(由BEGIN關鍵字標識);主循環執行輸入文件的代碼段;讀輸入文件以後的代碼段(由END關鍵字標識)。可參考下圖c++
awk 結構由模版和動做組成。模版用於篩選數據行,一般由正則或條件表達式構成;動做是由一對大括號包裹的代碼組成。他們都是可選的。正則表達式
#模式能夠是正則、條件表達式或兩者的結合。模式不須要寫在大括號內 #模式規定了觸發大括號內的動做的條件 awk '/root/' txt.log #只有模版,輸出含有root的行 awk -F : '$3 == $4' txt.log #只有模版,輸出uid=gid的行 awk -F : '{if($3 == $4) echo print $0}' txt.log #區別於模式,動做要寫在括號內 awk '/root/{print $0}' txt.log #{}中是動做 awk '{print $0}' txt.log #只有動做,表示處理全部輸入行 #範圍匹配 '/root/, /mail/' 等同於sed awk -F: '/root/, /daemon/' txt.log #多個語句 awk -F: '/root/{print $0}{print $1}' txt.log #一個模版只能結合一個動做大括號,後一個是新的開始
兩種調用模式:awk -F 域分隔符 'awk程序段' 輸入文件 或 awk -f xx.awk 輸入文件shell
記錄和域:awk 將文件行定義爲記錄,行中的字符串定義爲域。域之間用空格、Tab鍵或其它字符分割。$爲域操做符,$0表示整行記錄,$1...$n 表示第幾個域,也支持表達式 $(a+b) a,b 爲整數。-F指定域分隔符,能夠是單個字符或正則表達式,默認是空格,Tab被認爲是多個空格。字符串跟變量用雙引號拼接。數據庫
awk -F ':' '{print NF}' txt.log # 一個冒號 awk -F ':+' '{print NF}' txt.log # 爲正則時以貪婪匹配爲準且第一個字符不會被解析爲正則符號
不須要聲明能夠直接使用,類型是由其內容決定的,變量名區分大小寫。編程
數據類型:數字(整型和浮點型 )、字符串、null、數組數組
賦值語句跟C語言相同,再也不贅述,默認初始化爲0或空字符。bash
#變量的使用 awk -F ':' 'BEGIN{one=1;two=2;print res} {res+=$(one+two);print res' txt.log
awk 內置了許多有用的變量,可使用man命令細查,下邊列出經常使用的函數
變量名 | 釋義 |
---|---|
ARGC | 命令行中參數的個數 |
AGRIND | 命令行中當前文件的位置,下標從0開始 |
ARGV | 命令行參數的數組 |
ENVIRON | 環境變量管理數組 |
FILENAME | 當前文件名 |
FNR | 瀏覽每一個文件的記錄數 |
FS/RS | 域分隔符,默認空格 | 記錄分隔符,默認空格 |
IGNORECASE | 布爾值,爲真則忽略大小寫匹配 |
NF/NR | 當前記錄中域數量,每行有可能不一樣 | 當前記錄數,不一樣於FNR,它記錄的是總行數 |
OFMT/OFS/ORS | 數字輸出格式 | 輸出域分隔符、默認空格 | 輸出記錄分隔符,默認換行符 |
SUBSEP | 數組下標分隔符,默認\034,能夠用來模擬實現二維數組 |
awk 支持關聯數組,下標也能夠是變量。使用for (key in array) array[key] 來遍歷工具
#數組賦值、刪除【delete】、遍歷【for in】、長度【length()】 awk -F: '{name[NR]=$1;} END{print length(name);delete name[1];for(n in name) print n, name[n]}' txt.log #注意:name["a"]=3 if("a" in name) print "exist" in 能夠斷定鍵是否存在
能夠經過命令行參數將變量傳遞到awk 的BEGIN 塊裏,有兩種方式
#-v 參數傳遞變量 awk -v a=1 -v b="hi dude" 'BEGIN{print a, b}' #awk 腳本 ##======test.awk======== # {print a, b} ##====================== awk -f test.awk a=1 b="hi dude" txt.log #在begin模塊訪問不了參數變量
包括整數運算,比較運算符、邏輯運算符 跟C語言相同。只是多了 x~/y/ x!~ /y/ 兩個正則匹配符
#關係運算符 > >= < <= == != ~ !~ awk -F: '$0 ~ /root/' txt.log # 正則匹配符 awk -F: '$0 !~ /root/' txt.log # !表示非 awk -F: '$3>=20 {print $1}' txt.log # == != #條件表達式 awk -F: '{max=$4>$3 ? $4 : $3;print $0,max}' txt.log #布爾運算符 && || ! awk -F":+" 'NF == 6 || $1 ~ /root/ {print $0 " show"}' txt.log #算術運算 + - * /(非整除) % ^或** ++ -- awk -F: '{print $3 "+10=" $3+10, x+=1}' txt.log awk -F: '{print $3 "/2=" $3/3}' txt.log # 保留6位有效小數 awk -F: '/^$/ {++x} END{print "有"x"個空行"}' txt.log # 未初始化的整型默認爲0
if 語句同C語言一致,屬於動做語句。
#if 用法示例,多個語句須要大括號,之間分號間隔 awk -F: '{ if($1 ~/root/) msg="root";\ else if($1 ~/mail/) msg="mail";\ else msg="unkonwn"; }END{print msg}' txt.log
循環示例
#while 相似還有do while awk -F: '{i=1;while($i<=NF){print NF, $i, $i++;}}' txt.log #for 有兩種模式 for (n in array) 專用於數組 awk -F: '{for(i=1;i<=NF;i++)print NF,$i;}' txt.log #循環控制 continue break 與C語言同 next 會阻止其在同一個命令塊中後邊的命令,而後從頭執行 exit 會退出整個awk 命令塊,直接跳轉到END模塊(若是有)
也能夠自定義函數,使用較少,主要介紹系統函數。
#字符串函數示例 #sub(/正則/,"替換字符","目標字符串,可省略默認是$0"),使用的是貪婪匹配,且只替換第一次匹配 #gsub 與sub 語法格式相同,區別在因而所有替換 awk -F: '{sub(/r.+t/, "===");print}' txt.log #是貪婪匹配 #index(string, substring) 返回子串第一次出現的位置,下標從1開始 awk -F: 'BEGIN {print index("hello", "l")}' #length(string) 返回字符數,省略參數表示則默認爲$0 #substr(string,start=1,length),省略或超出總長都默認到末尾,不能爲負數 #match(string, /pattern/)返回第一次匹配的字串位置並保存在RSTART中,字串長度保存在RLENGTH,不匹配返回0 awk -F: 'BEGIN {start= match("Good old USA", /[A-Z]+$/);print RSTART,RLENGTH,start}' #toupper(str), tolower(str) 大小寫轉換,僅gawk支持;sprintf(str) 格式化輸出 #split(string,array,sep=FS),將返回的數組放到array中,默認分隔符爲FS,無匹配則返回整個字符到第一個元素中 awk -F: 'BEGIN{split("2017-11-29",date);print date[1];}' #時間函數 systime strftime #systime() 返回unix時間戳(秒) awk 'BEGIN{print systime()}' #strftime("格式符" [,時間戳=當前]) 格式符與C庫strftime 一致,可 man strftime 查看 awk 'BEGIN{print strftime("%D")}' #數學函數 int rand srand #int() 去掉小數部分,沒有舍入 #rand() 生成0-1的隨機小數,每次執行產生的值都同樣 awk '/root/{print rand()}' txt.log #執行兩遍,輸出的結果同樣 #srand(x) 生成rand的種子,x默認是時間戳 awk 'BEGIN{srand()} /root/{print 1 + int(25*rand())}' txt.log
#輸出重定向(>和>>), 文件路徑需要引號包裹,文件一旦被打開,必須明確關閉或等待awk程序結束 awk -F: '$3>20 {print $0>"/tmp/test.log"}' txt.log #輸入從新定向 getline 函數。它能夠從標準輸入、管道,外部文件獲取下一行輸入。 #會修改NF,NR,FNR,若是獲得一個記錄返回1,達到文件末尾返回0,出現錯誤返回-1 #從管道獲取 awk 'BEGIN{"date"|getline now;print now}' awk 'BEGIN{while("ls"|getline)print}' #從命令行獲取 awk 'BEGIN{printf "What is your name?";\ getline name <"/dev/tty"}\ $1~name{print "found"name"on line",NR"."}\ END{print "See ya,"name"."}' txt.log #從外部文件獲取 awk 'BEGIN{while(getline < "/etc/passwd">0)lc++;print lc}'
管道:若是在awk中已打開一個管道,那麼在打開下一個管道前必須關閉它,管道符號右邊能夠經過雙引號關閉管道。
system("linux shell") 能夠執行系統命令,正常的執行系統命令須要用雙引號包裹