1、awk相關知識詳解linux
1.awk簡介shell
(1)awk:報告生成器,格式化文本輸出express
(2)版本:數組
New awk(nawk)bash
GNU awk(gawk)tcp
2.基本用法ide
awk [option] 'program' var=value file...函數
awk [option] -f programfile var=value file...編碼
awk [option] 'BEGIN{action;...};pattern{action...};END{action...}' file...url
說明:
awk程序一般由:BEGIN語句塊,可以使用模式匹配的通用語句塊,END語句組成
program一般是被單引號引住
option:
-F 指明輸入時用到的分隔符,默認爲空格(連續空格當作一個空格)
-v var=value 自定義變量
3. awk工做原理
(1)分割符、域、記錄相關概念
<1>awk執行時,由分隔符分割的字段(域)標記$1,$2...成爲域標識,$0爲全部域;和shell中的變量$符含義不一樣
<2>文件的每一行爲一個記錄
(2)awk工做原理
第一步:執行BEGIN(action)語塊中的語句
第二步:從文件或標準輸入讀取一行,而後執行pattern{action;...}語句塊,它逐行掃描文件,從第一行到最後一行重複這個過程,直到文件所有被讀取
第三步:當讀至輸入流末尾時,執行END(action...)語句塊
說明:
BEGIN語句塊在awk開始從輸入流中讀取行以前被執行,這是一個可選的語句塊,好比變量初始化、打印輸出表格的表頭等語句一般能夠寫在BEGIN語句塊中,不可打印多個文件的行參數;只輸出一行;
END語句塊在awk從輸入流中讀取完全部的行以後即被執行,好比打印全部行的分析結果這類信息彙總都是在END語句塊中完成,它也是一個可選語句塊
pattern語句塊中的通用命令是最重要的部分,也是可選的。若是沒有提供pattern語句塊,則默認執行(print $0),即打印每個讀取到的行。
4.awk基本格式
awk [option] 'program' file...
program:pattern{action statements;...}
pattern和action
pattern語句決定動做語句什麼時候觸發(BEGIN END)
action statements 對數據進行處理,放在{}指明,(print,printf)
說明:同一個pattern語句塊的action之間用「;」隔離,print輸出的不一樣域之間用「,」隔離;省略action,默認執行print $0操做
5.print格式說明
print item1 ,item2....
注意:逗號分隔符
輸出的各item能夠字符串,也能夠是數值;當前記錄的字段、變量或awk的表達式
如省略item,至關於print $0
輸出內容除了變量,用雙引號括起來
舉例:
<1> 以「:」爲分隔符,顯示/etc/passwd每一行信息
awk –F: '{print}' /etc/passwd
<2>以「:」爲分隔符,把/etc/passwd每一行以wang信息代替
awk –F: ‘{print 「wang」}’ /etc/passwd
<3>以「:」爲分割符,顯示該文件每一行的第一個字段
awk –F: ‘{print $1}’ /etc/passwd
<4>在標準輸入的每一行輸出「hello,world」
6.printf命令詳解
<1>格式化輸出:printf "FORMAT" ,item1,item2,...
必須指定FORMAT
不會自動換行,須要顯式給出換行控制符,\n
PARMAT須要分別爲後面每一個item指定格式符
<2>格式符:與每一個item一 一對應
%c:顯示字符的ASCII編碼
%i:顯示十進制整數
%e:顯示科學計數法數值
%f:顯示爲浮點數
%g:以科學計數法或浮點形式顯示數值
%s:顯示字符串
%u:無符號整數
%%:%自己
<3>修飾符
#[.#]:第一個數字控制顯示的寬度,第二個表示小數點後的精度
-:左對齊(默認是右對齊)
+:顯示數值的正負符號
<4>實例
awk -F : '{printf "%s",$1}' /etc/passwd
awk -F: ‘{printf "Username: %-15s, UID:%d\n",$1,$3}’ /etc/passwd
疑問:在printf格式化輸出中,awk內置變量還有效嗎?
發現OFS變量並無生效,在printf語句中,格式化輸出在format設置就好
7.awk變量(引用的時候不用加$符號)
(1)內置變量
<1>FS(field separator):輸入字段分割符,默認爲空格
awk -F : '{print $1,$3}' /etc/passwd
awk -v FS=":" '{print $1,$3}' /etc/passwd
<2>OFS輸出字段分隔符,默認爲空格;
OFS默認爲空格:此時輸出字段間是以空格爲分隔符
OFS爲「+++」:
<3>RS(record separator)記錄輸入時分隔符,原換行符仍舊有效
新建文件內容以下
RS爲「 」:此時c d爲一行,只不過c後邊的原換行符依舊有效,故看起來不在一行
爲更深入的理解RS,看下邊兩圖
說明:由於awk輸出字段分割符默認是空格,原來的換行符會被覆蓋
<4>ORS:輸出記錄分割符,用指定符號代替換行符(此時原來的換行符仍是有效的)
新建文件內容以下:
ORS爲「+++」:
說明:ORS只是把空格轉換爲「+++」,原先的換行符並無轉換,由於c和e、h後邊是由換行符的,可是並無轉換
<5>NF字段數量
awk -F:‘{print NF}’ /etc/fstab
awk -F: '{print $(NF-1)}' /etc/passwd 顯示倒數第二個字段
<6>行號 NR
awk '{print NR}' /etc/fstab
awk END'{print NR}' /etc/fstab
<7>FNR 各文件分別統計行號
awk '{print FNR}' test test1
<8>FILENAME 當前文件名
awk '{print FILENAME}' test
<9>ARGC 命令行參數的個數
awk BEGIN'{print ARGC }' test test1
awk '{print ARGC }' test test1
<10>ARGV :數組,保存的是命令行給定的各參數(索引從0開始)
awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab
awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab
(2)自定義變量:
<1>在program中直接定義
<2>-v var=value 變量名區分大小寫
awk-v test='hello gawk' '{print test}' /etc/fstab
awk-v test='hello gawk' 'BEGIN{print test}'
awk'BEGIN{test="hello,gawk";print test}'
8.操做符
<1>算術操做符
x+y , x-y , x*y , x/y , x^y , x%y
-x:轉換爲負數
+x:轉換爲整數
awk -v x=1 -v y=2 'BEGIN{print x+y}'
<2>賦值操做符
=, +=, -=, *=, /=, %=, ^=
++, --
awk -v a=1 -v b=2 'BEGIN{print b+=a}'
<3>比較操做符
>, >=, <, <=, !=, ==
<4>模式匹配符:
~:左邊是否和右邊匹配包含 模式匹配的話,被匹配模式須要被/ /括起來
!~:是否不匹配
cat /etc/passwd|awk'$0 ~ /root/'|wc-l
cat /etc/passwd|awk'$0 !~ /root/'|wc-l
<5>邏輯操做符:&& || !
awk –F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
awk -F: '$3 ==0 || $3>=1000 {print $1}' /etc/passwd
awk -F: ‘!($3==0){print $1}' /etc/passwd
awk -F: '!($3>=500) {print $3}}' /etc/passwd
<6>條件表達式
selector?if-true-expression:if-false-expression
awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf"%15s:%-s\n",$1,usertype}' /etc/passwd
9.pattern:根據pattern條件,過濾匹配的行,再作處理
<1>若是未指定:空模式,匹配每一行
<2>/regular expression/:僅處理可以匹配到的行
awk'/^UUID/{print $1}' /etc/fstab
awk'!/^UUID/{print $1}' /etc/fstab
<3>relation expression:關係表達式;結果爲真纔會處理
真:結果非0,非空
假:結果爲空字符或0
實例:
awk -F: '$3<1000{print $1,$3}' /etc/passwd
awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
seq 10 | awk 'i=!i' 顯示奇數行;顯示偶數行的話,提早給i賦值爲1便可
awk -F: '""{print}' test 啥都不輸出
awk -F: 'i=1;j=1{print $1,$3}' test
<4>line ranges(行範圍)
」startline,endline「:/pat1/,/pat2/不支持直接給出數字格式
效果同樣:
awk-F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
awk-F: 'NR>=2&&NR<=10{print $1}' /etc/passwd
awk-F: '/^root/,/^nobody/{print $1}' /etc/passwd
<5> BEGIN/END模式
BEGIN{}: 僅在開始處理文件中的文本以前執行一次
END{}:僅在文本處理完成以後執行一次
10.經常使用的action
<1>Expression:算術,比較表達式
<2>Control Statements :if while 等
<3>compound statements:組合語句
<4>input statements
<5>output statements:print等
11.awk控制語句if-else
if (condition) statement [else statement]
if (condition1) {statement1} else if (condition2) {statement2} else {statement3}
說明:(若是statement爲多條命令,必須加「{}」,一條的話,能夠不加),通常狀況下仍是加上大括號比較好
實例:
awk BEGIN'{test=65;if(test>80) {print "it is good"} else if(test<60) {print "you are not ok"} else {print "you are right"}}'
awk-F: '{if($3>=1000)print $1,$3}' /etc/passwd
df-h|awk-F[%] '/^\/dev/{print $1}'|awk'{if($NF>=80) print $1}‘
12.awk控制語句while
while(condition)statement,條件真,進入循環;條件假,退出循環
使用場景:對一行內的多個字段逐一相似處理的時候
對數組中的各元素逐一處理時使用
實例:awk'/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg
awk'/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)}; i++}}' /etc/grub2.cfg
13.awk控制語句do-while
do statement while(condition) 不管真假,至少執行一次
實例: awk 'BEGIN{total=0;i=0;do{total+=i;i++}while(i<=100);print total}'
14.awk控制語句-for循環
for循環
語法:for(expr1;expr2;expr3) statement
for(variable assignment;condition;iterationprocess) {for-body}
特殊用法:可以遍歷數組中的元素;
語法:for(varin array) {for-body}
示例:
awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
15.awk控制語句switch
語法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; ...; default: statement}
16.awk控制語句break、continue、next
<1>awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0){continue}{sum+=i}};print sum}'
continue [n]
<2>awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==11){break}{sum+=i}};print sum}'
break [n]
<3>next 提早結束對本行處理而直接進入下一行處理(awk自身循環)
awk-F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
17.awk數組
<1>array["index-expression"]
index-expression:
可以使用任何字符串,但字符串須要用雙引號括起來(變量的話,就不用加了)
若是某數組元素事先不存在,在引用時,awk會自動建立此元素,並將其值初始化爲「空串」
若要判斷數組中是否存在元素,要使用「index in array」格式進行遍歷
實例一:
awk 'BEGIN{week["mon"]="monday";week["tue"]="tuesday";print week["mon"]}'
awk '!a[$0]++' test2
說明:命令三顯示的是test2文件的內容,命令三是爲了更好地理解「$0」與「arr[$0]」之間的關係,命令一是去掉test2中重複的行;
對命令一來講:應該把「arr[$0]「當作一個總體,例如當作「i」,此處用到i++和++i的相關知 識;arr[aa]=0-->!arr[aa]=1-->arr[aa]=1;arr[bb],arr[cc],arr[dd]相似;當再次到arr[aa]時,arr[aa]=1-->!arr[aa]++=0-->arr[aa]=2;若是第三次遇到arr[aa] 時,arr[aa]=2-->!arr[aa]++=0-->arr[aa]=3;
實例二:統計開放的tcp類型的端口的訪問狀態
<2>i++和++i的區別
awk 'BEGIN{i=0;print i++,i}'
awk 'BEGIN{i=0;print ++i,i}'
18.awk函數
(1)系統函數
<1>rand():返回0和1之間的一個隨機數
實例:
awk'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
執行awk 'BEGIN{print rand()}'
發現隨機數一直同樣
執行awk 'BEGIN{srand();print rand()}'
<2>length([s]):返回指定字符串的長度,裏邊的s是變量
實例:awk ’BEGIN{a="tian";print length(a)} ‘
<3>sub(r,s,[t]):對t字符進行搜索r表示的模式匹配的內容,並將第一個匹配到的內容替換爲s
<4>gsub(r,s,[t]):對t字符進行搜索r表示的模式匹配的內容,並將所有內容替換爲s
實例:
<5>split(s,array(),[r]):以r爲分隔符切割字符s,並將切割後的交過保存至array所表示的數組中(第一個索引值是1,日後依次累加)
實例:netstat-tan | awk'/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'
(2).自定義函數
格式:function name (parameter1,parameter2...){
statements
return expression
}
實例:
方法一:#cat fun.awk
function max(v1,v2) {
v1>v2?var=v1:var=v2
return var
}
END{a=3;b=2;print max(a,b);}
#awk –f fun.awktestfile
方法二: #cat fun.awk
function max(v1,v2) {
v1>v2?var=v1:var=v2
return var
}
END{print max(3,2)}
#awk –f fun.awktestfile
方法三:#cat fun.awk
#!/bin/awk -f
function max(v1,v2) {
v1>v2?var=v1:var=v2
return var
}
END{a=3;b=2;print max(a,b);}
#chmod u+x fun.awk
#fun.awk
19.awk中調用shell命令
system(命令)用來在awk命令中調用shell命令;(這是一個函數)
空格是awk中的字符串鏈接符,若是system中須要使用awk中的變量可使用空格分隔,
awk BEGIN'{system("hostname") }'
awk'BEGIN{a=12; system("echo " a) }'帶顏色部分是用來分離shell命令和awk變量的
20.awk腳本,將awk程序寫成腳本,直接調用或執行
直接調用
直接執行
21.向awk腳本傳遞參數
格式:awk.awk var=value var1=value1... inputfile
實例一:像腳本中傳遞參數
實例二:向直接執行的腳本中的函數傳遞參數
小結:發現像實例一 同樣直接給函數傳遞參數是不行的,必須以變量的形式傳遞參數
2、課後做業
一、統計/etc/fstab文件中每一個文件系統類型出現的次數
(1)查看/etc/fstab文件內容
(2)執行以下命令
二、統計/etc/fstab文件中每一個單詞出現的次數;
(1)查看/etc/fstab文件內容
(2)執行以下命令
3.新建以下文件,分別統計1班和2班的平均分
輸入以下命令
發現第二行的命令是正確的,由於第一行的命令沒讀取一行數據,s1和s2被從新賦值一次