一、三劍客簡介
grep: 文本過濾工具, (grep,egrep,fgrep) 文本搜索工具,根據用戶指定的“模式”對目標文件逐步進行匹配檢查,打印匹配到的行。
sed: 文本編輯工具,實現數據的替換,刪除,增加,選取等(以行爲單位進行處理)。
awk: 文本報告生成器,以字段爲單位進行處理(把一行的數據分割,然後進行處理)。
本文只介紹awk。
二、awk的介紹
1. awk的簡介
awk不僅是linux系統中的一個命令,還是一種編程語言,可以用來處理數據和生成報告(excel)。處理的數據可以是一個或多個文件,可以是來自標準輸入,也可以通過管道獲取標準輸入,awk可以在命令行上直接編輯命令進行操作,也可以編寫成awk程序來進行更爲複雜的運用。
awk的應用裏最重要的一個功能就是計數,而數組在awk裏最大的作用就是去重複。
2. awk的格式
awk指令是由模式,動作,或者模式和動作的組合組成。
awk [options] 'pattern{print} ' file
模式既pattern,可以類似理解成sed的模式匹配,可以由表達式組成,也可以是兩個正斜槓之間的正則表達式。比如NR==1,這就是模式,可以把他理解爲一個條件。 動作即action,是由在大括號裏面的一條或多條語句組成,語句之間使用分號隔開。
注意:
pattern和{action}需要用單引號引起來,防止shell作解釋。
pattern是可選的。如果不指定,awk將處理輸入文件中的所有記錄。如果指定一個模式,awk則只處理匹配指定的模式的記錄。
{action}爲awk命令,可以是但個命令,也可以多個命令。
整個action(包括裏面的所有命令)都必須放在{ }內。
action必須被{ }包裹,沒有被{ }包裹的就是patern
file要處理的目標文件
3. awk工作原理
awk 程序通常由:BEGIN語句塊、能夠使用模式匹配的通用語句塊、END語句塊,共3部分組成。
第一步:執行BEGIN{action;… }語句塊中的語句。
第二步:從文件或標準輸入讀取一行,然後執行pattern{ action;… }語句塊,逐行掃描文件,從第一行到最後一行重複這個過程,直到文件全部被讀取完畢。
第三步:當讀至輸入流末尾時,執行END{action;…}語句塊。
BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常可以寫在BEGIN語句塊中。
END語句塊在awk從輸入流中讀取完所有的行之後即被執行,比如打印所有行的分析結果這類信息彙總都是在END語句塊中完成,它也是一個可選語句塊。
pattern語句塊中的通用命令是最重要的部分,也是可選的。如果沒有提供pattern語句塊,則默認執行{ print },即打印每一個讀取到的行,awk讀取的每一行都會執行該語句塊。
4. 記錄與字段
awk對每個要處理的輸入數據認爲都是具有格式和結構的,而不僅僅是一堆字符串。默認情況下,每一行內容都是一條記錄,並以換行符分隔(\n)結束。
簡單來說: 記錄 = 行
字段,域 = 列
小結:
RS 記錄分隔符,表示每行的結束標誌
NR 行號(記錄號)
FS 字段分隔符,每列的分隔標誌或結束標誌
NF 就是每行有多少列,每個記錄中字段的數量
$ 符號表示取某個列(字段),$1$2$NF
NF 表示記錄中的區域(列)數量,$NF取最後一個列(區域。)
FS(-F)字段(列)分隔符,-F(FS)“:”<==>‘BEGIN{FS=':'}’
NR 行號
分隔符==>結束標識
5. awk變量
1,內置變量
FS:輸入字段分隔符
awk -v FS=':' '{print $1,$3}' /etc/passwd
先找一個文件/etc/passwd作爲參數,這樣可查看命令的結果。
OFS:輸出字段分隔符
awk -v FS=':' -v OFS=':' '{print $1,$3}' /etc/passwd
RS:輸入的記錄分隔符
awk -v FS="." -v RS=" " '{print $1}' chen
ORS:輸出的記錄分隔符
awk -v FS="." -v RS=" " -v ORS="#" '{print $1}' chen
NF:字段的數量
awk -F" " '{print NF}' /etc/fstab
NR:記錄號
awk '{print NR,$0}' /etc/fstab
FNR:各文件分別計數,行號
awk '{print FNR}' /etc/fstab /etc/inittab
FILENAME:當前文件名
awk '{print FILENAME}’ /etc/fstab
ARGC:命令行參數的個數
awk '{print ARGC}' /etc/fstab /etc/shadow
ARGV:數組,保存的是命令行所給定的各參數
awk 'BEGIN {print ARGV[2]}' /etc/fstab /etc/inittab
打印命令行的最後一個參數
awk 'BEGIN {print ARGV[ARGC-1]}' /etc/fstab /etc/inittab /etc/haha hi hello
2,自定義變量
(1) -v var=value
(2) 在program中直接定義
6. 輸出命令
1,輸出命令:print
用法:print item1,item2,...
item:字符串,用引號引用;
變量:顯示變量的值,可以直接使用變量的名進行引用;
數值:不加引號
要點:
(1)各item之間使用逗號分隔;輸出的分隔符默認爲空白字符;
(2)輸出的各item可以爲字符串或數值、當前記錄的字段($#)、變量或awk的表達式;數值會被飲食轉換爲字符串進行輸出;
(3)print後的item省略時,相當於運行"print $0" ,用於輸出整行;
(4)輸出空白字符:print " "
2,格式化輸出:printf
用法:printf “FORMAT”, item1, item2, ...
(1)必須指定FORMAT;
(2) 不會自動換行,需要顯式給出換行控制符,\n;
(3)FORMAT中需要分別爲後面每個item指定格式符;
格式符:與item一一對應
%c: 顯示字符的ASCII碼
%d, %i: 顯示十進制整數
%e, %E:顯示科學計數法數值
%f:顯示爲浮點數
%g, %G:以科學計數法或浮點形式顯示數值
%s:顯示字符串
%u:無符號整數
%%: 顯示%自身
舉例:
awk -F: '{printf "Username:%s UID:%s\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username:%-15s UID:%s\n",$1,$3}' /etc/passwd
awk -F: 'BEGIN{printf "%.d %.2f\n",1.73333,3.1111}'
修飾符:
#[.#]:第一個數字控制顯示的寬度;第二個#表示小數點後精度,%3.1f
-: 左對齊(默認右對齊) %-15s
+:顯示數值的正負符號 %+d
7. awk操作符
1, 算術操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x: 轉換爲負數
+x: 轉換爲數值
awk 'BEGIN{print 2^5}
2, 字符串操作符:沒有符號的操作符,字符串連接
3, 賦值操作符:
=, +=,
-=, *=, /=, %=, ^=
++, --
awk 'BEGIN{print i++;print i}' awk 'BEGIN{print ++i;print i}'
4, 比較操作符:
==, !=, >, >=, <, <=
awk -v FS=: '$3 == 0 {print $0}' /etc/passwd
5, 模式匹配符:
~:左邊是否和右邊匹配包含
!~:是否不匹配
awk '$0 ~ "^root" {print $0}' /etc/passwd
6, 邏輯操作符:與&&,或||,非!
awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
7, 函數調用: function_name(argu1, argu2, ...)
8, 條件表達式(三目表達式):
selector?if-true-expression:if-false-expression
9,關係表達式
爲非0時,即爲真,才處理
爲0或爲空時,不處理
!0=1 !Num=0 (Num爲任意非0的值)
舉例:
df |awk -v FS=% '$0 ~ "/dev/sd" {print $1}'|awk '$NF>=10 {printf "DevName:%-10s Used:%s%%\n",$1,$5}'
8. PATTERN
PATTERN:根據pattern條件,過濾匹配的行,再做處理
(1)如果未指定:空模式,匹配每一行
(2) /regular expression/:僅處理能夠模式匹配到的行,需要用/ /括起來
awk '/^UUID/{print $1}' /etc/fstab awk '!/^UUID/{print $1}' /etc/fstab
(3) relational expression: 關係表達式,結果爲“真”纔會被處理
真:結果爲非0值,非空字符串
假:結果爲空字符串或0值
(4) 行範圍:類似於vim sed 中的地址定界方式
cat /boot/grub/grub.conf |awk '/default/,/hidden/' 匹配以'/default/開始,以/hidden/結束'的範圍
(5) BEGIN/END模式
BEGIN{ }:僅在開始處理文件中的文本之前執行一次
END{ }:僅在文本處理完成之後執行
9. 控制語句
1,if-else
語法:
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}
else{statement3}
使用場景:
對awk取得的整行或某個字段做條件判斷
awk -v FS=: '{if($3>=1000){usertype="Common User"}else{usertype="Sys User"}printf "UserName:%-15s Type:%s\n",$1,usertype}' /etc/passwd
2,while循環
語法:
while(condition){statement;…}
條件“真”,進入循環;條件“假”,退出循環
使用場景:
對一行內的多個字段逐一類似處理時使用
對數組中的各元素逐一處理時使用
echo {1..10} |awk '{n=1;while(n<=NF){if($n%2==0){print $n,"oushuo"}eelse {print $n,"jishu"};n++}}'
3,do-while循環
語法:do {statement;…}while(condition)
意義:無論真假,至少執行一次循環體
4,for循環
語法:for(expr1;expr2;expr3) {statement;…}
常見用法:
for(variable assignment;condition;iteration process)
{for-body}
特殊用法:能夠遍歷數組中的元素
語法:for(var in array) {for-body}
5, switch語句
語法:switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
6, break和continue
break[n]:退出當前循環,n爲數字,用於指定推出幾層循環;
continue:提前結束本輪循環而進入下一輪;
awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i};print sum}'
awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==1)continue;sum+=i};print sum}'
7,next:提前結束對本行處理而直接進入下一行處理(awk自身循環)
awk -v FS=: '{if($3%2!=0) next;print $1,$3}' /etc/passwd
10. 數組
關聯數組:array[index-expression]
index-expression:
(1) 可使用任意字符串;字符串要使用雙引號括起來
(2) 如果某數組元素事先不存在,在引用時,awk會自動創建此元素,並將其值初始化爲“空串”;要判斷數組中是否存在某元素,要使用“index in array”格式進行遍歷。
數組遍歷:
若要遍歷數組中的每個元素,要使用for循環
for(var in array) {for-body}
注意:
var會遍歷array的每個索引
11. 函數
函數分爲內建函數和用戶自定義函數
1,內建函數
數值處理:rand():返回0至1之間的一個隨機數;
awk 'BEGIN{srand();print int(rand()*10000)}'
字符串處理:
length([s]):返回指定的字符串的長度。
awk 'BEGIN{print length("hello")
sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並將第一個匹配的內容替換爲s。
echo "2018:08:29 10:08:30" |awk 'sub(/:/,"-",$1)'
gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並全部替換爲s所表示的內容。
echo "2018:08:08 08:08:08" |awk 'gsub(/:/,"-",$1)' 匹配第一字段 echo "2018:08:08 08:08:08" |awk 'gsub(/:/,"-",$0)' 匹配所有
split(s,array,[r]):以r爲分隔符,切割字符串s,並將切割後的結果保存至array所表示的數組中。
netstat -tan
netstat -tan |awk '/^tcp\>/&& !($5 ~ "*") {split($5,ip,":");count[ip[1]]++}ENcount[ip[1]]++}END{for(i in count){print i,count[i]}}'
注意:awk的數組下標從開始編號。
substr(s,i[,n]):從s所表示的字符串中取出字串。取法:從i表示的位置開始,取n個字符。
三、總結
記住三個命令的運用形式
grep '字符' 文件
sed '命令' 文件
awk '條件{命令}' 文件
單引號內就是正則表達式的用法
重複一遍:單引號內一定是正則表達式!