1. 程式人生 > >【linux命令學習】— awk 命令學習

【linux命令學習】— awk 命令學習

文章目錄

一、awk 介紹

awk是linux上一款強大的文字分析工具,它可以將檔案逐行的讀入,然後用分割符分割開來,再對分割的各個部分進行處理。awk分割的各個部分叫做域,預設的分割符是空格和製表符。可以通過-F來指定分割符。

awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk,gawk 是 AWK 的 GNU 版本。

二、使用姿勢

主要語法

awk [引數] 'pattern{action}'

awk的使用看起來比較複雜,但是掌握好它的語法後,其實也很簡單。

和大多數的命令一樣,awk可以指定一些引數,也可以不傳任何引數。awk具體支援哪些引數讀者可以通過man awk檢視相關幫助文件。這裡就不多做介紹。

在引數後面跟著一個單引號括起來的執行語句,其中pattern表示過濾規則,支援正則表示式和邏輯表示式。如果pattern涉及多個條件,可以用 &&

|| 來關聯,分別表示與和或。pattern可以不填,表示不過濾任何資料。

pattern後面根據一個花括號括起來的真正的執行語句,比如 print $1 表示輸出分割後的第一個域。action{}可以有多個語句,以;號隔開。如果缺失action則表示輸出一整行的內容。和{print}以及{print $0}效果一樣

使用示例

假設有一段文字test.txt,有2個用逗號隔開的列,分別表示姓名、年齡。

jack,18
nick,24
joe,19
hack,19

輸出所有人的名字

awk -F , '{print $1}' test.txt

-F ,表示用逗號作為分割符,之後pattern

為空,action則為{print $1}。awk執行後,每一行都會分割成兩列,之後輸出第一列的資料。其中$1則表示第一列的資料, $2則表示第二列的資料,以此類推,$n則表示第n列的資料。要注意的是,$0表示的是這一整行的資料

輸出年齡小於20歲,並且名字中帶有ck內容的人(整行正則匹配)

awk -F , '/ck/ && $2 < 20{print}' test.txt

輸出年齡小於20歲,並且名字中沒有帶有ck內容的人(整行正則匹配)

awk -F , '!/ck/ && $2 < 20{print}' test.txt

上面用兩個斜槓//圍起來的就是正則表示式,awk會對每行進行正則匹配,匹配不上的就不會進行處理。

由於直接使用//匹配的是整行資料,所以如果我們的需求是要找名字中帶有ck內容的人的話,語句就不是很正確。因為如果這一行中剛好有其他欄位也包含了ck,那麼就可能造成誤匹配。那麼,怎麼就對名字這個欄位進行正則匹配呢?

輸出年齡小於20歲,並且名字中帶有ck內容的人(就對名字的欄位進行匹配)

awk -F , '$1 ~ /ck/ && $2 < 20{print}' test.txt

$1 ~ //則表示對第一列資料進行正則匹配,沒匹配上的列會被過濾。
$1 !~ //則表示對第一列資料進行正則匹配,匹配上的列會被過濾。

BEGIN和END關鍵字

action裡面的語句會對每一行過濾後的資料進行輸出,那麼,如果我們想在輸出的頭部和尾部增加一些內容,應該怎麼做呢?答案就是使用BEGIN和END關鍵字。記得一定要大寫

BEGIN後面跟一個語句塊{},表示在awk掃描文字前輸出一些內容。END用法也一樣,在awk掃描文字後輸出一些內容。

awk -F , 'BEGIN {print "name,age"} {print} END {print "end"}' test.txt
//輸出 
name,age
jack,18
nick,24
joe,19
hack,19
end

上面的語句我們可以看到有3個{}語句塊,分別表示掃描前語句塊掃描文字時使用的語句塊掃描後語句塊

內建變數

ARGC               命令列引數個數
ARGV               命令列引數排列
ENVIRON            支援佇列中系統環境變數的使用
FILENAME           awk瀏覽的檔名
FNR                瀏覽檔案的記錄數,也就是記錄所在的行數
FS                 設定輸入域分隔符,等價於命令列 -F選項
NF                 瀏覽記錄的域的個數
NR                 已讀的記錄數
OFS                輸出域分隔符
ORS                輸出記錄分隔符
RS                 控制記錄分隔符

awk內建了一些變數,我們可以在語句塊直接使用 。

直接輸出第2行的資料

awk -F , 'FNR==2 {print}' test.txt

print和printf的區別

awk中同時提供了print和printf兩種列印輸出的函式。

其中print函式的引數可以是變數、數值或者字串。字串必須用雙引號引用括起來,引數必須用逗號分隔,不然多個引數之間連在一起會造成混淆。

printf和c語言中的printf基本一樣,可以格式化字串。

print輸出例子

awk -F , '{print "name="$1",""age="$2}' test.txt

printf輸出例子

awk -F , '{printf "name=%s,age=%0.2f\n",$1,$2}' test.txt

//輸出
name=jack,age=18.00
name=nick,age=24.00
name=joe,age=19.00
name=hack,age=19.00

通過printf,我們可以將年齡轉化成小數點

三、awk 指令碼

通過 -f scriptfile 來將awk執行語句放到指令碼中。我們可以編寫一個awk指令碼test.awk

BEGIN {print "name,age"}
$2 < 20 && /ck/ {print $1}
END {print "end"}

之後執行

awk -F , -f test.awk test.txt

等同於執行

awk -F , 'BEGIN {print "name,age"}  $2 < 20 && /ck/ {print $1} END {print "end"}'

awk指令碼也可以這麼寫

#!/usr/bin/awk -f
BEGIN {print "name,age"}
$2 < 20 && /ck/ {print $1}
END {print "end"}

之後直接執行該指令碼即可

./test.awk -F , test.txt

四、awk 程式設計

定義變數

awk語句中可以直接定義變數然後使用

# 設定count變數,統計一共有多少行
awk -F , '{count++;print $0} END {print count}' test.txt
# 設定count變數的初始值為1
awk -F , 'BEGIN{count=1} {count++;print $0} END {print count}' test.txt

我們可以在BEGIN語句塊中設定變數的初始值,如果print要輸出一個沒有定義過的變數,awk也不會報錯,而是輸出空字串。

條件語句

awk的條件語句也和C語言基本一樣。

# 如果歲數小於20歲並且名字欄位帶有ck,輸出的歲數就+5,否則就+1
awk -F , '{if($2<20 && $1 ~ /ck/){print $1,$2+5}else{print $1,$2+1}}' test.txt

上面的語句就是我們常見的if…else,很好理解。

迴圈語句

awk的迴圈語句也和C語言基本一樣。支援while、do/while、for、break、continue這些關鍵字。

# 每一行重複輸出3次
awk -F, 'BEGIN{i=0} {while(i<3){print $0;i++};i=0}' test.txt
awk -F, '{for(i=0;i<3;i++){print $0}}' test.txt

陣列

awk的陣列的下標可以是數字或者字母,這和js的map比較像。

# 輸出的過程中,遇到名字是nick的,把它的名字轉換成 hello 。最後我們再輸出一個world
awk -F, 'BEGIN{nickname["nick"]="hello";nickname[1]="world"} {if(nickname[$1]!=""){print nickname[$1],$2}else{print $1,$2}} END{print nickname[1]}' test.txt

上面的語句在BEGIN塊中定義了nickname的陣列,同時使用了兩種下標,分別是"nick"和數字1。之後在後面也用到了。

五、寫在結尾

awk是linux上一款處理文字的神器,以前看到或者要用的時候總是習慣去百度,然後直接抄過來改一點東西,而沒有去較系統的學習一下。主要還是被它那看似複雜的語句塊嚇住,今天在認真看了幾篇awk教程後發現其本質也很簡單,學習起來其實很快。個人覺的有程式設計基礎的人,差不多半個小時就足以將awk掌握個大概。

當然,要深入的學習awk肯定不是一件簡單的事,本篇部落格也只是對awk的語句進行一些簡單的介紹,也足以應付我們工作中大部分的需求。如果想深入學習awk的同學可以去官方文件http://www.gnu.org/software/gawk/manual/gawk.html學習看看。