细说awk
細(xì)說awk
awk是一個(gè)處理文本的編程語言工具,能用簡(jiǎn)短的程序處理標(biāo)準(zhǔn)輸入或文件、數(shù)據(jù)排序、計(jì)算以及生成報(bào)表等。
awk的基本語法:
awk option ‘pattern {action}’ fileawk選項(xiàng)
-f program-file //從文件中讀取awk程序源文件 -F fs //指定fs為輸入字段分隔符 -v var=value //變量賦值 --posix //兼容POSIX正則表達(dá)式 --dump-variables=[file] //把a(bǔ)wk命令時(shí)的全局變量寫入文件,默認(rèn)文件是awkvars.out --profile=[file] //格式化awk語句到文件,默認(rèn)是awkprof.outawk模式
BENG{} //給程序賦予初始狀態(tài),先執(zhí)行的工作 END{} //程序結(jié)束之后執(zhí)行的一些結(jié)尾工作 /reqular expression/ //為每個(gè)輸入記錄匹配正則表達(dá)式 pattern && pattern //邏輯and,滿足兩個(gè)模式 pattern || pattern //邏輯or,滿足其中一個(gè)模式 ! pattern //邏輯not,不滿足模式 pattern1,pattern2 //連續(xù)范圍匹配示例:
1)從文件讀取awk程序處理文件
2)指定輸入分隔符,指定多個(gè)分隔符
tail -2 /etc/passwd|awk 'BEGIN{FS=":"}{print $1}' tail -2 /etc/passwd|awk -F: -f test.awk a="ass;gg#sow;p#slolow;wpw#pp" echo $a|awk -F'[;#]+' '{print $3}' //以下是顯示的內(nèi)容 sow3)變量賦值
awk -v a=$a 'BEGIN{print a}' //引用系統(tǒng)變量 ass;gg#sow;p#slolow;wpw#ppawk 'BEGIN{print '$a'}' //會(huì)報(bào)語法錯(cuò)誤,是因?yàn)樽兞坷锖刑厥夥?hào) a=123 awk 'BEGIN{print '$a'}' 123 awk -v a=linux 'BEGIN{print a}' linux4)輸出awk全局變量到文件
5)BEGIN、END、--profile
6)/reg/正則匹配
awk 'BEGIN{FS=":"}$1~/root/' /etc/passwd root:x:0:0:root:/root:/bin/bashawk -F: 'BEGIN{OFS="=="}/^bin/,/^adm/{print $1,$3,$5}' /etc/passwd bin==1==bin daemon==2==daemon adm==3==admawk 'BEGIN{FS=":";OFS=";"}{print $1,$2}' /etc/passwd|head -n5 root;x bin;x daemon;x adm;x lp;xawk內(nèi)置變量
FS 輸入字段分隔符,默認(rèn)是空格或制表符 OFS 輸出字段分隔符,默認(rèn)是空格 RS 輸入記錄分隔符,默認(rèn)是換行符\n ORS 輸出記錄分隔符,默認(rèn)是換行符\n NF 統(tǒng)計(jì)當(dāng)前記錄中字段個(gè)數(shù) NR 統(tǒng)計(jì)記錄編號(hào),每處理一行記錄,編號(hào)就會(huì)加1 FNR 統(tǒng)計(jì)記錄編號(hào),每處理一行記錄會(huì)加1,處理第二個(gè)文件時(shí),編號(hào)會(huì)重新計(jì)數(shù) ARGC 命令行參數(shù)數(shù)量 ARGIND 當(dāng)前正在處理的文件索引值 ARGV 命令行參數(shù)數(shù)組序列數(shù)組,下標(biāo)從0開始,ARGV[0]是awk ENVIRON 當(dāng)前系統(tǒng)的環(huán)境變量 FILENAME 輸出當(dāng)前處理的文件名 IGNORECASE 忽略大小寫 SUBSEP 數(shù)組中下標(biāo)的分隔符,默認(rèn)為‘\034’ seq -f 'user%02g' 10|sed 'n;n;a\-------'|awk 'BEGIN{RS="-+"}{print $1}' user01 user04 user07 user10seq 2 8|awk 'BEGIN{ORS="+"}{print $0}' 2+3+4+5+6+7+8+awk -F: '$1~/^root/{$5="ROOT";$NF="";print $0}' /etc/passwd root x 0 0 ROOT /rootawk -F: '{sum+=$3}END{print sum}' /etc/passwd 2605awk -F: 'NR<=3{print NR":"$0}' /etc/passwd 1:root:x:0:0:root:/root:/bin/bash 2:bin:x:1:1:bin:/bin:/sbin/nologin 3:daemon:x:2:2:daemon:/sbin:/sbin/nologinecho -e 'a\nb\nc' > a echo -e 'd\ne\nf' > b awk '{print NR,FNR,$0}' a b //NR每處理一行就會(huì)加1,FNR在處理第二個(gè)文件時(shí),行號(hào)重新計(jì)數(shù) 1 1 a 2 2 b 3 3 c 4 1 d 5 2 e 6 3 fARGC是命令行參數(shù)個(gè)數(shù)
awk 'BEGIN{print ARGC}' 1 2 3 //awk后有多少個(gè)參數(shù),以空格為分隔 4ARGV是將命令行參數(shù)存到數(shù)組,元素同ARGC指定,數(shù)組下標(biāo)從0開始
awk 'BEGIN{print ARGV[0],ARGV[1],ARGV[2]}' aa bb awk aa bbARGIND是當(dāng)前正在處理的文件索引值,第一個(gè)文件是1,第二個(gè)是2,以此類推
awk '{print ARGIND,$0}' a b 1 a 1 b 1 c 2 d 2 e 2 fENVIRON調(diào)用系統(tǒng)變量
awk 'BEGIN{print ENVIRON["SHELL"]}' /bin/bash[root@localhost prictice]# a=123 [root@localhost prictice]# awk 'BEGIN{print ENVIRON["a"]}'[root@localhost prictice]# export a [root@localhost prictice]# awk 'BEGIN{print ENVIRON["a"]}' 123FILENAME是當(dāng)前處理文件的文件名
[root@localhost prictice]# awk 'BEGIN{print "文件名\t文件名對(duì)應(yīng)的每行內(nèi)容"}FNR==NR{print FILENAME"-->"$0}FNR!=NR{print FILENAME"->"$0}' a b 文件名 文件名對(duì)應(yīng)的每行內(nèi)容 a-->a a-->b a-->c b->d b->e b->fIGNORECASE忽略大小寫
[root@localhost ~]# echo "A a b c"|xargs -n1|awk 'BEGIN{IGNORECASE=1}/A/' A a三目運(yùn)算符
seq 5|awk '{print $0%2==1?"yes":"no"}' yes no yes no yes seq 6|awk '{print n=(n?n","$0:$0)}' 1 1,2 1,2,3 1,2,3,4 1,2,3,4,5 1,2,3,4,5,6 seq 6|awk '{print NR%2?$0:$0"\n我是每隔2行增加的內(nèi)容"}' 1 2 我是每隔2行增加的內(nèi)容 3 4 我是每隔2行增加的內(nèi)容 5 6 我是每隔2行增加的內(nèi)容 seq 6|awk '{printf NR%2!=0?$0" ":$0" \n"}' 或 seq 6|awk 'ORS=NR%2?" ":"\n"' 或 seq 6 |awk '{if(NR%2)ORS=" ";else ORS="\n";print}' 1 2 3 4 5 6if語句
seq 3|awk '{if($0==3){print $0}}' 3 seq 3|awk '{if($0==3)print "yes";else print "no"}' no no yes head -2 /etc/passwd|awk -F: '{if($1=="root"){print $0} else if($1=="ftp"){print $0} else print "no"}' root:x:0:0:root:/root:/bin/bash nowhile語句
[root@localhost ~]# cat file 1 2 3 4 5 6 7 8 9 [root@localhost ~]# awk '{i=1;while(i<=NF){printf $i" ";i++};print ""}' file 1 2 3 4 5 6 7 8 9for語句
awk '{for(i=1;i<=NF;i++){printf $i" "};{print ""}}' file awk '{for(i=NF;i>=1;i--){printf $i" "};{print ""}}' file 3 2 1 6 5 4 9 8 7 echo "192.168.221.10 192.168.221.20 192.168.221.30"|awk '{for(i=1;i<=NF;i++)printf "\047"$i"\047";print ""}' '192.168.221.10''192.168.221.20''192.168.221.30'break、continue
awk 'BEGIN{for(i=1;i<=5;i++){if(i==3){break};print i}}' awk 'BEGIN{for(i=1;i<=5;i++){if(i==3){continue};print i}}'數(shù)組
tail -3 /etc/passwd|awk -F: '{a[NR]=$1}END{print a[1],a[2],a[3]}' //數(shù)組下標(biāo)從1開始 postfix sshd chronytail /etc/passwd|awk -F: '{a[NR]=$1}END{for(i=1;i<=NR;i++)print i":::"a[i]}' 1:::operator 2:::games 3:::ftp 4:::nobody 5:::systemd-network 6:::dbus 7:::polkitd 8:::postfix 9:::sshd 10:::chrony awk -F: '{a[NR]=$1}END{for(i in a)print i"---"a[i]}' /etc/passwd 17---postfix 4---adm 18---sshd 5---lp 19---chrony 6---sync 7---shutdown 8---halt 9---mail 10---operator 11---games 12---ftp 13---nobody 14---systemd-network 1---root 15---dbus 2---bin 16---polkitd 3---daemon tail -5 /etc/passwd|awk -F: '{a[x++]=$1}END{for(i=0;i<=x-1;i++)print i"=="a[i]}' 0==dbus 1==polkitd 2==postfix 3==sshd 4==chrony awk -F: '{a[$NF]++}END{for(v in a)print a[v]"\t"v}' /etc/passwd 1 /bin/sync 1 /bin/bash 15 /sbin/nologin 1 /sbin/halt 1 /sbin/shutdownawk -F: '{a[$NF]++}END{for(i in a) if(a[i]>2)print a[i]"\t"i}' /etc/passwd 15 /sbin/nologin netstat -tlnp|awk '/^tcp/{a[$6]++}END{for(i in a)print a[i]"\t"i}' 4 LISTEN awk -F: '{if(a[$NF]++)print $1}' /etc/passwd //打印shell重復(fù)對(duì)應(yīng)的用戶名(但不打印重復(fù)的起始的那個(gè)) awk -F: '{if(!a[$NF]++)print $1}' /etc/passwd //與上面相反統(tǒng)計(jì)每個(gè)相同字段對(duì)應(yīng)的另一個(gè)字段的總和
tail /etc/services |awk -F'[ /]+' '{a[$1]+=$2}END{for(v in a)print v,a[v]}' com-bardac-dw 97112 3gpp-cbsp 48049 iqobject 97238 matahari 49000 isnetserv 96256 blp5 96258多維數(shù)組
awk 'BEGIN{a["x","y"]=123;for(v in a)print v,a[v]}' xy 123 awk 'BEGIN{SUBSEP=":";a["x","y"]=123;for(v in a)print v,a[v]}' x:y 123 cat ip.txt A 192.168.1.1 B 192.168.1.2 B 192.168.1.2 C 192.168.1.1 C 192.168.1.1 D 192.168.1.4 //根據(jù)指定的字段統(tǒng)計(jì)出現(xiàn)次數(shù) awk 'BEGIN{SUBSEP="-"}{a[$1,$2]++}END{for(v in a)print a[v],v}' ip.txt 1 D-192.168.1.4 1 A-192.168.1.1 2 C-192.168.1.1 2 B-192.168.1.2內(nèi)置函數(shù)
int(expr) // 截?cái)酁檎麛?shù) sqrt(expr) //平方根 rand() //返回一個(gè)隨機(jī)數(shù)N,0和1范圍,0<N<1 srand([expr]) //使用expr生成隨機(jī)數(shù),如果不指定,默認(rèn)使用當(dāng)前時(shí)間為種子,如果前面有種子則使用生成隨機(jī)數(shù) asort(a,b) //對(duì)數(shù)組a的值進(jìn)行排序,把排序后的值存到新的數(shù)組b中,新排序的數(shù)組下標(biāo)從1開始 asorti(a,b) //對(duì)數(shù)組a的下標(biāo)進(jìn)行排序,同上 sub(r,s[, t]) //對(duì)輸入的記錄用s替換r,t可選針對(duì)某字段,但只替換第一字符串 gsub(r,s [, t]) //對(duì)輸入的記錄用s替換r,t可選針對(duì)某字段替換,替換所有字符串 index(s,t) //返回s中字符串t的索引位置,0為不存在 length([s]) //返回s的長(zhǎng)度 match(s,r [, a]) //測(cè)試字符串s是否包含匹配r的字符串 split(s,a [,r [, seps]]) //根據(jù)分隔符seps將s分成數(shù)組 substr(s,i [, n]) //截取字符串s從i開始到長(zhǎng)度n,如果n沒有指定則是剩余部分 tolower(str) //str中的所有大寫轉(zhuǎn)換成小寫 toupper(str) //str中的所有小寫轉(zhuǎn)換成大寫 systime() //當(dāng)前時(shí)間戳 strftime([format [, timestamp [, utc-flag]]]) //格式化輸出時(shí)間,將時(shí)間戳轉(zhuǎn)為字符串示例
int()
echo "11ab11 012ab ab123"|xargs -n1|awk '{print int($0)}' 11 12 0sqrt()
awk 'BEGIN{print sqrt(81)}' 9rand()、srand()
awk 'BEGIN{print rand()}' //不是每次運(yùn)行就是一個(gè)隨機(jī)數(shù),會(huì)一直保持一個(gè)不變 awk 'BEGIN{srand();print rand()}' //會(huì)生成一個(gè)變化的隨機(jī)數(shù) awk 'BEGIN{srand();print int(rand()*10)}' //[0-10)之間的整數(shù)asort()、asorti()
//asort(a,b)將數(shù)組a的每個(gè)元素的值進(jìn)行排序放到數(shù)組b中,b數(shù)組的下標(biāo)從1開始,返回值是數(shù)組b元素的個(gè)數(shù) seq -f "str%.g" 5|awk '{a[x++]=$0}END{s=asort(a,b);for(i=1;i<=s;i++)print b[i],i}' str1 1 str2 2 str3 3 str4 4 str5 5 //asorti(a,b)將數(shù)組a的下標(biāo)進(jìn)行排序放到數(shù)組b中,b數(shù)組的下標(biāo)從1開始,返回值是數(shù)組b元素的個(gè)數(shù) seq -f 'str%.g' 5|awk '{a[x++]=$0}END{s=asorti(a,b);for(i=1;i<=s;i++)print b[i],i}' 0 1 1 2 2 3 3 4 4 5sub() 、gsub()
//匹配“blp5”的行中含有“tcp”的替換成“icmp” tail /etc/services |awk '/blp5/{sub(/tcp/,"icmp");print $0}' blp5 48129/icmp # Bloomberg locator blp5 48129/udp # Bloomberg locator //匹配“blp5”的行中含有“c"替換成“9” tail /etc/services |awk '/blp5/{gsub(/c/,"9");print $0}' blp5 48129/t9p # Bloomberg lo9ator blp5 48129/udp # Bloomberg lo9ator //針對(duì)第二個(gè)字段將2的值替換成7 echo "1 2 2 3 4 5"|awk 'gsub(2,7,$2){print $0}' //將數(shù)字替換成0 echo "1 2 3 a b c"|awk 'gsub(/[[:digit:]]/,'0'){print $0}' 0 0 0 a b c //在指定行前后加一行 seq 5|awk 'NR==2{sub('/.*/',"txt\n&")}{print}' seq 5|awk 'NR==2{sub('/.*/',"&\ntxt")}{print}'index()
tail -n5 /etc/services |awk '{print index($2,"tcp")}' //“tcp”在$2中的位置 7 0 7 0 7length()
//統(tǒng)計(jì)字段的長(zhǎng)度 head -n3 /etc/passwd|awk -F: '{print length($1)}' 4 3 6 //統(tǒng)計(jì)數(shù)組的長(zhǎng)度 awk -F: '{user[x++]=$1}END{print length(user)}' /etc/passwd 19split(string,array,delimiter)
echo "http://www.baidu.com/admin/index.php"|awk '{split($0,a,"/|//");for(k in a)print a[k],k}' index.php 4 http: 1 www.baidu.com 2 admin 3substr(string,index,length)
echo "http://www.baidu.com/admin/index.php"|awk '{print substr($0,1,7)}' http://toupper(string)
echo "www.baidu.com"|awk '{print toupper($0)}' WWW.BAIDU.COMtolower(string)
echo "WWW.badu.com"|awk '{print tolower(substr($0,1,3))}' www返回當(dāng)前時(shí)間戳
awk 'BEGIN{print systime()}' 1521527470將時(shí)間戳轉(zhuǎn)為日期和時(shí)間
echo "1521527470"|awk '{print strftime("%F %T",$0)}' 2018-03-20 14:31:10i/o語句
getline //設(shè)置$0來自下一個(gè)輸入記錄 getline var //設(shè)置var來自下一個(gè)記錄 command | getline [var] //運(yùn)行命令管道輸出到$0或var next //停止當(dāng)前處理的輸入記錄 print //打印當(dāng)前記錄 printf fmt,expr-list //格式輸出 printf fmt,expr-list > file //格式輸出和寫到文件 system(cmd-line) //執(zhí)行命令和返回狀態(tài) print ... >> file //追加輸出到文件 print ... | command //打印輸出作為命令輸入getline
seq 5 |awk '/3/{print;getline;sub(".*","&*");print}' 3 4*getline var
cat name.txt zhangsan lisi wangwu zhaoliucat age.txt 26 18 30 36awk '{getline var < "age.txt";print $0,var}' name.txt zhangsan 26 lisi 18 wangwu 30 zhaoliu 36 [root@localhost ~]# cat name.txt zhangsan 12 lisi 12 wangwu 12 zhaoliu 12 [root@localhost ~]# cat age.txt 26 18 30 36修改name.txt將第二字段全部成age.txt中的數(shù)據(jù) awk '{getline line < "age.txt";gsub($2,line,$2);print}' name.txt zhangsan 26 lisi 18 wangwu 30 zhaoliu 36 [root@localhost ~]# awk 'BEGIN{"seq 5" |getline var;print var}' 1 [root@localhost ~]# awk 'BEGIN{while("seq 5"|getline)print}' 1 2 3 4 5next
seq 5|awk '{if($0==3){next}else{print}}' //1,2,4,5 seq 5|awk 'NR==1{next}{print $0}' //2,3,4,5 seq 5|awk 'NR!=1{print}' //2,3,4,5 cat a hello 1 a 2 b 3 cawk 'NR==1{s=$0}NF!=1{print s,$0}' a 或 awk 'NR==1{s=$0}NF!=1{print s,$0}' a hello 1 a hello 2 b hello 3 csystem()
awk 'BEGIN{if(system("grep -wE ^root /etc/passwd &> /dev/null")==0)print "yes";else print "no"}' yes將結(jié)果寫入到文件中
awk -F: '{a[$NF]++}END{for(i in a)print a[i],i > "state.txt"}' /etc/passwd cat state.txt 1 /bin/sync 1 /bin/bash 15 /sbin/nologin 1 /sbin/halt 1 /sbin/shutdown管道連接shell命令
awk -F: 'NR>2&&NR<18{print $0 | "grep ftp"}' /etc/passwd ftp:x:14:50:FTP User:/var/ftp:/sbin/nologinprintf語句
格式化輸出,默認(rèn)打印字符串不換行
格式:printf [format] arguments
%s //一個(gè)字符串 %d,%i //一個(gè)小數(shù) %f //一個(gè)浮點(diǎn)數(shù) %.ns //輸出字符串,n是輸出幾個(gè)字符 %ni //輸出整數(shù),n是輸出幾個(gè)數(shù)字 %m.nf //輸出浮點(diǎn)數(shù),m是輸出整數(shù)位數(shù),n是輸出的小數(shù)位數(shù) %x //不帶正負(fù)號(hào)的十六進(jìn)制,使用a至f表示10到15 %X //不帶正負(fù)號(hào)的十六進(jìn)制,使用A至F表示10至15 %% //輸出單個(gè)% %-5s //左對(duì)齊,對(duì)參數(shù)每個(gè)字段左對(duì)齊,寬度為5 %-4.2f 左對(duì)齊,寬度為4,保留兩位小數(shù) %5s 右對(duì)齊,不加橫線表示右對(duì)齊 vim test.awk BEGIN{ print "+--------------------+--------------------+"; printf "|%-20s|%-20s|\n","Name","Number"; print "+--------------------+--------------------+"; } awk -f test.awk +--------------------+--------------------+ |Name |Number | +--------------------+--------------------+自定義函數(shù)
awk 'function myfunc(a,b){return a+b}BEGIN{print myfunc(1,2)}' 3nginx日志格式
'$remote_addr $http_x_forwarded_for [$time_local]' ' $host "$request_uri" $status' ' "$http_referer" "$http_user_agent"'
//統(tǒng)計(jì)ip訪問次數(shù) awk '{a[$1]++}END{for(i in a)print i,a[i]}' /tmp/access.log 127.0.0.1 5 192.168.221.1 125 192.168.221.10 16 //統(tǒng)計(jì)訪問大于100次的ip awk '{a[$1]++}END{for(i in a)if(a[i]>100)print i,a[i]}' /tmp/access.log 192.168.221.1 125 //統(tǒng)計(jì)訪問ip次數(shù)倒序排列 awk '{a[$1]++}END{for(i in a)print i,a[i]|"sort -k2 -nr"}' /tmp/access.log 192.168.221.1 125 192.168.221.10 16 127.0.0.1 5 //統(tǒng)計(jì)上一分鐘訪問量 date=$(date -d '-1 min' +%d/%b/%Y:%H:%M) awk -v date=$date '$3~date{c++}END{print c}' /tmp/access.log //統(tǒng)計(jì)訪問最多的一個(gè)頁面 awk '{a[$6]++}END{for(v in a)print v,a[v]|"sort -k2 -nr|head -1"}' /tmp/access.log //統(tǒng)計(jì)每個(gè)ip訪問狀態(tài)碼為404的次數(shù) awk '{if($7~/404/)a[$1" "$7]++}END{for(i in a)print i,a[i]}' /tmp/access.log //統(tǒng)計(jì)每個(gè)ip訪問狀態(tài)碼數(shù)量 awk '{a[$1" "$7]++}END{for(v in a)print v,a[v]}' /tmp/access.log轉(zhuǎn)載于:https://blog.51cto.com/13480443/2088360
總結(jié)
- 上一篇: JDK1.8源码(二)——java.la
- 下一篇: redis中的五种基本的数据结构