awk、grep和sed被稱爲linux三劍客,事實上grep和awk我在平常工做中也經常使用到(sed用的比較少),可能有些人對awk瞭解比較少,我先大概介紹下。 不少人覺得awk只是一個文本處理工具,實際上他們也是這麼用的。但事實上它實際上是一門語言,擁有數學運算符、進程控制語句,甚至針對於文本處理封裝了不少內置變量和函數,這造就了它強大的文本處理能力。 若是grep只能作到數據的篩選,那awk還能作到數據的處理、分析甚至生成報表,畢竟它是一門完整的編程語言。html
由於這篇文章不是awk的入門教程,若是想入門的話我推薦阮一峯老師的awk 入門教程 和 左耳朵耗子的AWK 簡明教程 。 linux
回到我今天的正題,今天我給你們看個我常使用awk的場景。由於作後端開發,常常在作數據分析的時候會有這樣的問題,1.面對幾十萬條的數據,須要篩選出幾百幾千個特定key的數據。2.對這幾百萬條數據,針對其中的id字段補齊其餘字段。 sql
這時候可能有精通excel的同窗跳出來講 「就這,so easy,vlookup就搞定!」 ,事實上,excel確實能夠解決問題,但有點重,甚至有些時候咱們在服務器上還用不了excel。還有啥其餘方法?針對我說的這倆場景,其實仔細想一下,是否是sql中倆表join就能解決問題。實際上你並不須要真正把文件灌到數據庫裏,只須要用awk一條命令就能解決。shell
咱們把問題具像下,假設有兩個文件,score.txt存着學號+成績的數據,另一個name.txt存着學號+姓名的數據,你如今想知道每一個人都烤了多少分。 數據庫
score.txt編程
id score 1 87 2 67 3 68 4 75 5 90 6 100 7 0
name.txt後端
id name 1 張三 2 李四 3 王五 4 趙二 5 劉能 6 熊大
你想獲得一份包含學號 姓名和成績的數據,就像下面這樣。bash
id score name 1 87 張三 2 67 李四 3 68 王五 4 75 趙二 5 90 劉能 6 100 熊大 7 0
用awk生成這樣的數據有多簡單?只須要一行代碼,你能夠保存name.txt和score.txt,而後執行下面命令嘗試下。服務器
awk 'ARGV[1]==FILENAME {map[$1]=$2} ARGV[2]==FILENAME {print $0, map[$1]}' name.txt score.txt
簡簡單單就實現了name.txt和score.txt在id之上的right join。 編程語言
解釋下上面的代碼,ARGV和FILENAME是awk內置的變量,ARGV裏存放在awk所接受的參數列表,像上面 ARGV[1]就是"name.txt",ARGV[2]就是"score.txt"。awk是面向行的,因此針對每一行數據都會執行ARGV[1]==FILENAME {map[$1]=$2} ARGV[2]==FILENAME {print $0, map[$1]}
,每一行數據都會屬於某個文件,FILENAME標識出當前行所屬的文件名,像在括號{}
前的ARGV[1]==FILENAME
你能夠看作是其餘語法中的條件判斷,你能夠認爲它就是省略了if,但和if的功能是一致的。
因此上述代碼的含義就是 若是當前行是輸入name.txt的,就把學號和姓名存在map裏(awk裏的變量不用預先聲明)。 若是當前行是屬於score.txt,就從map裏把姓名找出來,而後把數據輸出。
awk 'ARGV[1]==FILENAME {map[$1]=$2} ARGV[2]==FILENAME {print $0, map[$1]}' name.txt score.txt
針對於不一樣的數據,只須要調整下$後面的具體值,能夠實現用不一樣的列做爲key來作join,其實這裏並不比sql的join複雜,但在linux服務器上卻很方便。上網中我只是實現了right join,若是在print $0, map[$1]
前加上if (length(map[$1]) > 0)
就能夠實現inner join。left join的話也只須要把文件名換一下。
知道了這些,awk實現多文件的交集、差集等操做都不在話下。另外不要忘記了awk其實也是一門編程語言,因此它也能夠實現不少很複雜的邏輯,你能夠把代碼在某個文件裏而後用-f參數調起,好比我以前老師用awk作一些簡單的統計工做,好比計算均值、總和…… awk簡直堪稱後端工程師提效利器。