首頁>技術>

awk、grep和sed被稱為linux三劍客,事實上grep和awk我在日常工作中也常用到(sed用的比較少),可能有些人對awk瞭解比較少,我先大概介紹下。 很多人以為awk只是一個文字處理工具,實際上他們也是這麼用的。但事實上它其實是一門語言,擁有數學運算子、程序控制語句,甚至針對於文字處理封裝了很多內建變數和函式,這造就了它強大的文字處理能力。 如果grep只能做到資料的篩選,那awk還能做到資料的處理、分析甚至生成報表,畢竟它是一門完整的程式語言。

回到我今天的正題,今天我給大家看個我常使用awk的場景。因為做後端開發,經常在做資料分析的時候會有這樣的問題,1.面對幾十萬條的資料,需要篩選出幾百幾千個特定key的資料。2.對這幾百萬條資料,針對其中的id欄位補齊其他欄位。

這時候可能有精通excel的同學跳出來說 “就這,so easy,vlookup就搞定!” ,事實上,excel確實可以解決問題,但有點重,甚至有些時候我們在伺服器上還用不了excel。還有啥其他方法?針對我說的這倆場景,其實仔細想一下,是不是sql中倆表join就能解決問題。實際上你並不需要真正把檔案灌到資料庫裡,只需要用awk一條命令就能解決。

例項

我們把問題具像下,假設有兩個檔案,score.txt存著學號+成績的資料,另外一個name.txt存著學號+姓名的資料,你現在想知道每個人都烤了多少分。

score.txt

id score 1 872 673 684 755 906 1007 0

name.txt

id name 1 張三2 李四3 王五4 趙二5 劉能6 熊大

你想得到一份包含學號 姓名和成績的資料,就像下面這樣。

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簡直堪稱後端工程師提效利器

19
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Apache Druid 高效能的實時分析型資料庫