0,簡介
Linux awk
是一個實用的文本處理工具
,它不僅是一款工具軟件,也是一門編程語言
。awk
的名稱來源於其三位作者的姓氏縮寫,其作者分別是Alfred Aho
,Peter Weinberger
和 Brian Kernighan
。
如果你在linux 系統中追蹤awk
,可以看到其最終指向的是/usr/bin/gawk
,也就是gawk
命令。其GNU官方手冊 權威且全面,但對於初學者並不是很友好,因爲內容非常多,你可能不知從何看起。對於普通用戶,一般也用不到非常複雜的功能。
如果一個文件由規則的多個列
組成,則非常適合使用awk
來處理。本文介紹awk
常用方法,對於普通使用者應該是足夠了。
1,基本概念
awk
命令會對文本文件
的每一行
進行處理,其語法格式如下:
awk `參數` `pattern {action}` `filename`
pattern
是要匹配的規則,action
是要執行的動作,只有匹配了pattern
的行
,纔會執行動作action
。
這句命令的含義是:對於文件filename
的每一行,如果能夠符合條件pattern
,則執行動作action
。如果不寫pattern
,則表示對於文件filename
的每一行,都進行action
處理。
1.1,參數
awk
最常使用的參數是-F
,其後跟一個分隔符
或者正則表達式
,其表示的意思是以怎樣的規則
對每一行進行分割。 默認是空格
或Tab鍵
。
1.2,pattern
pattern
可以是下表中的任意一項:
pattern | 說明 |
---|---|
/正則表達式/ |
正則寫在兩個/ 之間 |
關係表達式 |
由awk 中支持的關係運算符 組成 |
模式匹配表達式 |
由 ~ (匹配)和!~ (不匹配)組成 |
BEGIN{語句} |
在處理第一行 文本之前,執行BEGIN 塊 中的語句,可以在這裏進行一些變量初始化等操作 |
END{語句} |
在處理完最後一行 文本之後,執行END 塊 中的語句 |
/規則1/,/規則2/ |
這是一個範圍模板 ,只處理規則1 第一次出現與規則2 第一次出現之間的行 |
1.3,action
action
由awk
語句組成,比如print
,用於輸出。
2,awk 內置變量
awk
中內置了很多變量,來方便使用,這裏介紹一些常用的:
awk 內置變量 |
含義 |
---|---|
FS |
表示分隔符 ,類似-F 參數的功能 |
$0 |
一行的完整內容 |
$n |
用分隔符 隔開的第n 列,比如$1 表示第一列 |
FILENAME |
當前文件名 |
NR |
當前行數,即當前行 是第幾行 |
NF |
當前行的列數,即當前行 被分割符 分成了幾列 |
IGNORECASE |
如果爲真,表示忽略大小寫進行匹配 |
3,awk 內建函數
awk
常用函數如下:
函數 | 含義 |
---|---|
tolower() |
字符串轉小寫 |
toupper() |
字符串轉大寫 |
length() |
計算字符串長度 |
split() |
字符串分割 |
systime() |
Unix 時間戳 |
strftime() |
時間格式化,用法同C語言 中的strftime 函數 |
rand() |
隨機數 |
sin() |
正弦 |
cos() |
餘弦 |
sqrt() |
平方根 |
exp() |
求冪 |
4,awk 運算符
awk
支持如下常用運算符
:
運算符 | 含義 |
---|---|
+ - * / & |
加,減,乘,除,求餘 |
= += -= *= /= %= ^= **= |
賦值 運算符 |
< <= > >= != == |
比較 運算符 |
空格 |
用於連接字符串 ,使用較多 |
|| |
邏輯或 |
&& |
邏輯與 |
! |
邏輯非 |
~ |
匹配 |
!~ |
不匹配 |
5,awk 使用案例
假如,我們有如下文件,分別爲姓名
,性別
,年齡
,成績
,等級
和省份
:
>>> cat log.txt
_________________
小明,男,23,550^優秀---北京
小麗,女,22,560^優秀---河北
小磊,男,24,530^良好---河南
小召,男,23,540^優良---山東
小欣,女,23,545^優良---山西
5.1 使用-F
以逗號,
爲分隔符
,並將第1列,第2列和第3列輸出,如下:
>>> awk -F, '{print $1,$2,$3}' log.txt
______________________________________
小明 男 23
小麗 女 22
小磊 男 24
小召 男 23
小欣 女 23
當分隔符
只有一個字符
時,分割符
可以緊挨-F
,還有如下幾種寫法:
awk -F , '{print $1,$2,$3}' log.txt #`分隔符`與`-F`之間有一個空格
awk -F',' '{print $1,$2,$3}' log.txt #`分隔符`用單引號引住,並且緊挨`-F`
awk -F"," '{print $1,$2,$3}' log.txt #`分隔符`用雙引號引住,並且緊挨`-F`
awk -F ',' '{print $1,$2,$3}' log.txt #`分隔符`用單引號引住,與`-F`之間有空格
awk -F "," '{print $1,$2,$3}' log.txt #`分隔符`用雙引號引住,與`-F`之間有空格
當分隔符
有多個連續字符
時,必須用雙引號
或者單引號
引住分割符
,可以緊挨-F
,也可以有空格
:
awk -F '---' '{print $2}' log.txt #`分隔符`用單引號引住,與`-F`之間有空格
awk -F"---" '{print $5}' log.txt #`分隔符`用雙引號引住,與`-F`之間沒有空格
以上兩個命令輸出的內容一樣,此時分隔符
爲---
,每一行都被分成了兩列,如下:
小明,男,23,550^優秀 北京
小麗,女,22,560^優秀 河北
小磊,男,24,530^良好 河南
小召,男,23,540^優良 山東
小欣,女,23,545^優良 山西
當有多個單獨的分割符
時,將多個分隔符寫在中括號[]
中,如下,表示以,
或者以---
爲分隔符:
>>> awk -F "[,^]" '{print $1, $2, $3, $4, $5}' log.txt
________________________
小明 男 23 550 優秀---北京
小麗 女 22 560 優秀---河北
小磊 男 24 530 良好---河南
小召 男 23 540 優良---山東
小欣 女 23 545 優良---山西
5.2 使用內置變量
我們用變量NR
輸出當前行號
,變量NF
輸出當前行的列數
,變量FILENAME
輸出當前文件名
,如下:
>>> awk -F"---" '{print NR, $1, $2, NF, FILENAME}' log.txt
__________________________________________________________
1 小明,男,23,550^優秀 北京 2 log.txt
2 小麗,女,22,560^優秀 河北 2 log.txt
3 小磊,男,24,530^良好 河南 2 log.txt
4 小召,男,23,540^優良 山東 2 log.txt
5 小欣,女,23,545^優良 山西 2 log.txt
5.3 如何連接字符串
我們將每一列使用豎線|
分割,方法是將分隔符
用雙引號
引住,然後緊挨變量
,如下:
>>> awk -F"---" '{print NR"|"$1"|"$2"|"NF"|"FILENAME}' log.txt
__________________________________
1|小明,男,23,550^優秀|北京|2|log.txt
2|小麗,女,22,560^優秀|河北|2|log.txt
3|小磊,男,24,530^良好|河南|2|log.txt
4|小召,男,23,540^優良|山東|2|log.txt
5|小欣,女,23,545^優良|山西|2|log.txt
5.3 使用內置函數
使用內置函數systime()
輸出時間戳,如下:
>>> awk -F"---" '{print NR"|"$1"|"$2"|"NF"|"FILENAME"|"systime()}' log.txt
—————————————————————————————————————————————
1|小明,男,23,550^優秀|北京|2|log.txt|1587022443
2|小麗,女,22,560^優秀|河北|2|log.txt|1587022443
3|小磊,男,24,530^良好|河南|2|log.txt|1587022443
4|小召,男,23,540^優良|山東|2|log.txt|1587022443
5|小欣,女,23,545^優良|山西|2|log.txt|1587022443
使用length
輸出行長度
大於5 的行:
>>> awk 'length>5' log.txt
——————————————————————————
小明,男,23,550^優秀---北京
小麗,女,22,560^優秀---河北
小磊,男,24,530^良好---河南
小召,男,23,540^優良---山東
小欣,女,23,545^優良---山西
5.4 使用pattern
使用pattern
只輸出男
同學信息,$0
表示每一行的原始內容,如下:
>>> awk '/男/ {print NR"|"$0}' log.txt
__________________________
1|小明,男,23,550^優秀---北京
3|小磊,男,24,530^良好---河南
4|小召,男,23,540^優良---山東
5.5 使用邏輯非!
使用邏輯非!
,輸出不爲男
的學生信息:
>>> awk '!/男/ {print NR"|"$0}' log.txt
__________________________
2|小麗,女,22,560^優秀---河北
5|小欣,女,23,545^優良---山西
5.6 使用關係表達式
使用關係表達式
,輸出年齡爲23 的學生信息:
# 以逗號分割後的第三列爲年齡
>>> awk -F, '$3==23 {print $3, $0}' log.txt
____________________________
23 小明,男,23,550^優秀---北京
23 小召,男,23,540^優良---山東
23 小欣,女,23,545^優良---山西
也可以寫成如下方式,輸出年齡爲23或25 的學生信息:
>>> awk -F, '$3==23 || $3==25' log.txt
________________________
小明,男,23,550^優秀---北京
小召,男,23,540^優良---山東
小欣,女,23,545^優良---山西
5.7 使用模式匹配表達式
使用模式匹配表達式
,輸出年齡爲24 的學生信息:
awk -F, '$3 ~/24/ {print $3, $0}' log.txt
24 小磊,男,24,530^良好---河南
5.8 使用if 語句
awk
也支持if 語句
,輸出年齡爲22 的學生信息,if 語句
寫在大括號{}
內:
>>> awk -F, '{if($3==22) print $3, $0}' log.txt
___________________________
22 小麗,女,22,560^優秀---河北
5.9 使用NR 輸出基數行
# `NR % 2 == 1` 爲基數行
>>> awk -F, 'NR % 2 == 1 {print NR, $0}' log.txt
——————————————————————————
1 小明,男,23,550^優秀---北京
3 小磊,男,24,530^良好---河南
5 小欣,女,23,545^優良---山西
5.10 使用NF 輸出倒數第一列
$(NF)
爲倒數第1列,$(NF-1)
爲倒數第2列,$(NF-2)
爲倒數第3列,依次類推。
如下輸出倒數第1列:
>>> awk -F, '{print $(NF)}' log.txt
______________
550^優秀---北京
560^優秀---河北
530^良好---河南
540^優良---山東
545^優良---山西
5.11 使用BEGIN 塊
BEGIN 塊
中可以是任意多個合法的awk 語句
。
>>> awk -F, 'BEGIN{print "姓名", "性別", "年齡"} {print $1, $2, $3}' log.txt
____________
姓名 性別 年齡
小明 男 23
小麗 女 22
小磊 男 24
小召 男 23
小欣 女 23
5.12 使用END 塊
END 塊
中可以是任意多個合法的awk 語句
,BEGIN 塊
與END 塊
可以一起使用。
>>> awk -F, 'BEGIN{print "姓名", "性別", "年齡"} {print $1, $2, $3} END{print "共有"NR"行信息"}' log.txt
____________
姓名 性別 年齡
小明 男 23
小麗 女 22
小磊 男 24
小召 男 23
小欣 女 23
共有5行信息
5.13 使用範圍模板
輸出小麗和小欣之間的行數據:
>>> awk '/小麗/,/小欣/' log.txt
______________________________
小麗,女,22,560^優秀---河北
小磊,男,24,530^良好---河南
小召,男,23,540^優良---山東
小欣,女,23,545^優良---山西
(完。)