zoukankan      html  css  js  c++  java
  • 三剑客——awk

    一、awk简介

    1.1 awk概述

    • awk是一种编程语言,主要用于在Linux/UNIX下对文件和数据进行处理,是Linux/UNIX下的一个工具。数据可以来自标准输入、一个或多个文件,或其它命令的输出;
    • awk的处理文件和数据的方式:逐行扫描文件,默认从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行需要的操作;

    1.2 awk的作用

    1)awk用来处理文件和数据的,是类UNIX下的一个工具,也是一种编程语言;
    2)可以用于统计数据,比如网站的访问量、访问的IP量等等;
    3)支持条件判断,支持for和while循环;

    二、awk的使用方式

    2.1 命令行模式使用

    1)语法结构
    awk 选项 '命令部分' 文件名
    
    特别说明:
    引用shell变量需用双引号引起
    
    2)常用选项

    1)-F 定义字段分割符,默认的分割符是空格;
    2)-v定义变量并赋值;

    3)命令部分说明
    • 正则表达式,地址定位;
    '/root/{awk语句}'             sed中: '/root/p'
    'NR==1,NR==5{awk语句}'            sed中: '1,5p'
    '/^root/,/^ftp/{awk语句}'     sed中:'/^root/,/^ftp/p'
    
    • {awk语句1;awk语句2;...}
    '{print $0;print $1}'       sed中:'p'
    'NR==5{print $0}'               sed中:'5p'
    注:awk命令语句间用分号间隔
    
    • BEGIN……END……
    'BEGIN{awk语句};{处理中};END{awk语句}'
    'BEGIN{awk语句};{处理中}'
    '{处理中};END{awk语句}'
    

    2.2 脚本模式使用

    1)脚本编写
    #!/bin/awk -f       定义魔法字符
    以下是awk引号里的命令清单,不要用引号保护命令,多个命令用分号间隔
    BEGIN{FS=":"}
    NR==1,NR==3{print $1"	"$NF}
    ...
    
    2)脚本执行
    方法1:
    awk 选项 -f awk的脚本文件  要处理的文本文件
    awk -f awk.sh filename
    
    sed -f sed.sh -i filename
    
    方法2:
    ./awk的脚本文件(或者绝对路径)  要处理的文本文件
    ./awk.sh filename
    
    ./sed.sh filename
    

    三、awk内部相关变量

    变量 变量说明 备注
    $0 当前处理行的所有记录
    $1,$2,$3...$n 文件中每行以间隔符号分割的不同字段 awk -F: '{print $1,$3}'
    NF 当前记录的字段数(列数) awk -F: '{print NF}'
    $NF 最后一列 $(NF-1)表示倒数第二列
    FNR/NR 行号
    FS 定义间隔符 'BEGIN{FS=":"};{print $1,$3}'
    OFS 定义输出字段分隔符,默认空格 'BEGIN{OFS=" "};print $1,$3}'
    RS 输入记录分割符,默认换行 'BEGIN{RS=" "};{print $0}'
    ORS 输出记录分割符,默认换行 'BEGIN{ORS=" "};{print $1,$3}'
    FILENAME 当前输入的文件名

    3.1 常用内部变量举例

    # awk -F: '{print $1,$(NF-1)}' passwd
    //显示文件的第一列和倒数第二列
    # awk -F: '{print $1,$(NF-1),$NF,NF}' passwd
    //显示文件的第一列和倒数第一、二列,并统计每行有多少列
    # awk '/root/{print $0}' passwd
    //打印出文件中包含root的行
    # awk '/root/' passwd
    //同上
    # awk -F: '/root/{print $1,$NF}' passwd
    //打印包含root的第一列和最后一列
    # awk -F: '/root/{print $0}' passwd
    //打印包含root的整列信息
    # awk 'NR==1,NR==5' passwd
    //打印文件的第1~5行
    # awk 'NR==1,NR==5{print $0}' 1.txt
    //同上
    # awk 'NR==1,NR==5;/^root/{print $0}' 1.txt 
    //打印文件中以root开头的1~5行
    

    3.2 内置变量分割符举例

    FS和OFS:
    # awk 'BEGIN{FS=":"};/^root/,/^lp/{print $1,$NF}' passwd
    # awk -F: 'BEGIN{OFS="		"};/^root/,/^lp/{print $1,$NF}' passwd
    # awk -F: 'BEGIN{OFS="@@@"};/^root/,/^lp/{print $1,$NF}' passwd
    
    RS和ORS:
    # awk 'BEGIN{RS="	"};{print $0}' 1.txt
    # awk 'BEGIN{ORS="	"};{print $0}' 1.txt
    

    四、awk工作原理

    awk -F: '{print $1,$3}' /etc/passwd
    

    1)awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符(RS)结束;
    2)每行被间隔符:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始;
    3)awk使用print函数打印字段,打印出来的字段会以空格分隔,因为$1,$3之间有一个逗号。逗号比较特殊,它映射为另一个内部变量,称为输出字段分隔符OFS,OFS默认为空格;
    4)awk处理完一行后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕

    五、awk使用进阶

    5.1 格式化输出print和printf

    print函数     类似echo "hello world"
    
    # date |awk '{print "Month: "$2 "
    Year: "$NF}'
    # awk -F: '{print "username is: " $1 "	 uid is: "$3}' /etc/passwd
    
    printf函数        类似echo -n
    
    # awk -F: '{printf "%-15s %-10s %-15s
    ", $1,$2,$3}'  /etc/passwd
    # awk -F: '{printf "|%15s| %10s| %15s|
    ", $1,$2,$3}' /etc/passwd
    # awk -F: '{printf "|%-15s| %-10s| %-15s|
    ", $1,$2,$3}' /etc/passwd
    
    awk 'BEGIN{FS=":"};{printf "%-15s %-15s %-15s
    ",$1,$6,$NF}' a.txt
    
    %s 字符类型 
    %d 数值类型 
    %-15s:字符类型,占15字符,并且左对齐
    - 表示左对齐,默认是右对齐
    printf默认不会在行尾自动换行,加
    
    

    5.2 awk变量定义

    # awk -v NUM=3 -F: '{ print NUM }' /etc/passwd
    # awk -v num=1 'BEGIN{print num}' 
    1
    # awk -v num=1 'BEGIN{print $num}' 
    
    注意:awk中调用定义的变量不需要加$
    

    5.3 awk中BEGIN……END使用

    ①BEGIN:表示在程序开始前执行;
    ②END :表示所有文件处理完后执行;
    ③用法:'BEGIN{开始处理之前};{处理中};END{处理结束后}';

    1)举例

    打印最后一列和倒数第二列(登录的shell和家目录)

    awk -F: 'BEGIN{ print "Login_shell		Login_home
    *******************"};{print $NF"		"$(NF-1)};END{print "************************"}' passwd
    
    awk 'BEGIN{ FS=":";print "Login_shell	Login_home
    *******************"};{print $NF"	"$(NF-1)};END{print "************************"}' passwd
    

    5.4 awk和正则的总和运用

    运算符 说明
    == 等于
    != 不等于
    > 大于
    < 小于
    >= 大于等于
    <= 小于等于
    ~ 匹配
    !~ 不匹配
    ! 逻辑非
    && 逻辑与
    || 逻辑或
    1)举例
    # awk -F: 'NR==1,/^lp/{print $0 }' passwd  
    //从第一行开始匹配到以lp开头行
    # awk -F: 'NR==1,NR==5{print $0 }' passwd
    //从第一行到第5行          
    # awk -F: '/^lp/,NR==10{print $0 }' passwd 
    //从以lp开头的行匹配到第10行       
    # awk -F: '/^root/,/^lp/{print $0}' passwd
    //从以root开头的行匹配到以lp开头的行       
    # awk -F: '/^root/ || /^lp/{print $0}' passwd
    # awk -F: '/^root/;/^lp/{print $0}' passwd
    打印以root开头或者以lp开头的行            
    # awk -F':' 'NR>=5 && NR<=10 {print $0}' /etc/passwd     
    # awk -F: 'NR<10 && NR>5 {print $0}' passwd 
    //显示5-10行  
    # awk 'NR>=30 && NR<=39 && $0 ~ /bash$/{print $0}' passwd 
    //打印30-39行以bash结尾的内容
    # awk 'NR>=3 && NR<=8 && /bash$/' passwd 
    //打印3~8以bash结尾的行
    # awk 'NR>=1 && NR<=5 && $0 ~ /^root/{print $0}' passwd
    //打印文件中1-5并且以root开头的行
    # awk 'NR>=1 && NR<=5 && $0 !~ /^root/{print $0}' passwd
    //同上(取反)
    # ifconfig eth0|awk 'NR>1 {print $2}'|awk -F':' 'NR<2 {print $2}'    
    # ifconfig eth0|grep Bcast|awk -F':' '{print $2}'|awk '{print $1}'
    # ifconfig eth0|grep Bcast|awk '{print $2}'|awk -F: '{print $2}'
    
    # ifconfig eth0|awk NR==2|awk -F '[ :]+' '{print $4RS$6RS$8}'
    # ifconfig eth0|awk -F"[ :]+" '/inet addr:/{print $4}'
    //打印IP地址
    

    5.5 awk的脚本编程

    1)流程控制语句

    ① if结构

    格式:awk 选项 '正则,地址定位{awk语句}'  文件名
    
    { if(表达式){语句1;语句2;...}}
    
    # awk -F: '{if($3>=500 && $3<=60000) {print $1,$3} }' passwd
    # awk -F: '{if($3==0) {print $1"是管理员"} }' passwd 
    # awk 'BEGIN{if('$(id -u)'==0) {print "admin"} }'
    

    ② if..else结构

    格式:{if(表达式){语句;语句;...}else{语句;语句;...}}
    
    # awk -F: '{ if($3>=500 && $3 != 65534) {print $1"是普通用户"} else {print $1,"不是普通用户"}}' passwd 
    # awk 'BEGIN{if( '$(id -u)'>=500 && '$(id -u)' !=65534 ) {print "是普通用户"} else {print "不是普通用户"}}'
    

    ③ if...elif...else结构

    格式:{ if(表达式1){语句;语句;...}else if(表达式2){语句;语句;...}else if(表达式3){语句;语句;...}else{语句;语句;...}}
    
    # awk -F: '{ if($3==0) {print $1,":是管理员"} else if($3>=1 && $3<=499 || $3==65534 ) {print $1,":是系统用户"} else {print $1,":是普通用户"}}'
    # awk -F: '{ if($3==0) {i++} else if($3>=1 && $3<=499 || $3==65534 ) {j++} else {k++}};END{print "管理员个数为:"i "
    系统用户个数为:"j"
    普通用户的个数为:"k }'
    # awk -F: '{if($3==0) {print $1,"is admin"} else if($3>=1 && $3<=499 || $3==65534) {print $1,"is sys users"} else {print $1,"is general user"} }' passwd
    # awk -F: '{  if($3==0) {print $1":管理员"} else if($3>=1 && $3<500 || $3==65534 ) {print $1":是系统用户"} else {print $1":是普通用户"}}'   passwd
    # awk -F: '{if($3==0) {i++} else if($3>=1 && $3<500 || $3==65534){j++} else {k++}};END{print "管理员个数为:" i RS "系统用户个数为:"j RS "普通用户的个数为:"k }' passwd
    # awk -F: '{ if($3==0) {print $1":是管理员"} else if($3>=500 && $3!=65534) {print $1":是普通用户"} else {print $1":是系统用户"}}' passwd 
    # awk -F: '{if($3==0){i++} else if($3>=500){k++} else{j++}} END{print i; print k; print j}' passwd
    # awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理员个数: "i; print "普通用个数: "k; print "系统用户: "j}' passwd 
    # awk -F: '{if($3>=1 && $3<500 || $3 == 65534) {print $1} else if($3>=500 && $3<=60000 ) {print $NF} }' passwd
    
    2)循环语句

    ① for循环

    # for ((i=1;i<=5;i++));do echo $i;done
    # awk 'BEGIN { for(i=1;i<=5;i++) {print i} }'
    //打印1~5
    # for ((i=1;i<=10;i+=2));do echo $i;done|awk '{sum+=$0};END{print sum}'
    # awk 'BEGIN{ for(i=1;i<=10;i+=2) {print i} }'
    # awk 'BEGIN{ for(i=1;i<=10;i+=2) print i }'
    //打印1~10中的奇数
    # awk 'BEGIN{sum=0;for(i=1;i<=5;i++) sum+=i;print sum}'
    # awk 'BEGIN{for(i=1;i<=5;i++) (sum+=i);{print sum}}'
    # awk 'BEGIN{for(i=1;i<=5;i++) (sum+=i);print sum}'
    //计算1-5的和
    

    ② while循环

    # i=1;while (($i<=5));do echo $i;let i++;done
    # awk 'BEGIN { i=1;while(i<=5) {print i;i++} }'
    //打印1-5
    # awk 'BEGIN{i=1;while(i<=10) {print i;i+=2} }'
    //打印1~10中的奇数
    # awk 'BEGIN{i=1;sum=0;while(i<=5) {sum+=i;i++}; print sum }'
    # awk 'BEGIN {i=1;while(i<=5) {(sum+=i) i++};print sum }'
    //计算1-5的和
    

    ③ 嵌套循环

    # awk 'BEGIN { for(y=1;y<=5;y++) { for(x=1;x<=y;x++) {printf x};print} }'
    # awk 'BEGIN{ y=1;while(y<=5) { for(x=1;x<=y;x++) {printf x};y++;print}}'
    //打印的图形
    1
    12
    123
    1234
    12345
    # awk 'BEGIN{for(y=1;y<=9;y++) { for(x=1;x<=y;x++) {printf x"*"y"="x*y"	"};print} }'
    # awk 'BEGIN{for(y=1;y<=9;y++) { for(x=1;x<=y;x++) printf x"*"y"="x*y"	";print} }'
    # awk 'BEGIN{i=1;while(i<=9){for(j=1;j<=i;j++) {printf j"*"i"="j*i"	"};print;i++ }}'
    # awk 'BEGIN{for(i=1;i<=9;i++){j=1;while(j<=i) {printf j"*"i"="i*j"	";j++};print}}'
    //打印九九乘法表
    

    ④ 控制循环

    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}}'
    

    5.6 awk算数运算

    + - * / %(模) ^(幂2^3)
    可以在模式中执行计算,awk都将按浮点数方式执行算术运算
    # awk 'BEGIN{print 1+1}'
    # awk 'BEGIN{print 1**1}'
    # awk 'BEGIN{print 2**3}'
    # awk 'BEGIN{print 2/3}'
    

    六、awk实战

    6.1 统计系统中各种类型的shell

    # awk -F: '{ shells[$NF]++ };END{for (i in shells) {print i,shells[i]} }' /etc/passwd
    

    6.2 统计网站访问状态

    # ss -antp|grep 80|awk '{states[$1]++};END{for(i in states){print i,states[i]}}'
    
    # ss -an |grep :80 |awk '{states[$2]++};END{for(i in states){print i,states[i]}}'
    
    # ss -an |grep :80 |awk '{states[$2]++};END{for(i in states){print i,states[i]}}' |sort -k2 -rn
    

    6.3 统计访问网站的每个IP的数量

    # netstat -ant |grep :80 |awk -F: '{ip_count[$8]++};END{for(i in ip_count){print i,ip_count[i]} }' |sort
    
    # ss -an |grep :80 |awk -F":" '!/LISTEN/{ip_count[$(NF-1)]++};END{for(i in ip_count){print i,ip_count[i]}}' |sort -k2 -rn |head
    

    6.4 统计网站日志中PV量

    统计Apache/Nginx日志中某一天的PV量  <统计日志>
    # grep '27/Jul/2017' mysqladmin.cc-access_log |wc -l
    
    统计Apache/Nginx日志中某一天不同IP的访问量 <统计日志>
    # grep '27/Jul/2017' mysqladmin.cc-access_log |awk '{ips[$1]++};END{for(i in ips){print i,ips[i]} }' |sort -k2 -rn |head
    
    # grep '07/Aug/2017' access.log |awk '{ips[$1]++};END{for(i in ips){print i,ips[i]} }' |awk '$2>100' |sort -k2 -rn
    

    名词解释:

    • 网站浏览量(PV):指页面的浏览次数,用以衡量网站用户访问的网页数量。多次打开同一页面则浏览量累计。用户每打开一个页面便记录1次PV;
    • 访问次数(VV): 从访客来到您网站到最终关闭网站的所有页面离开,计为1次访问。若访客连续30分钟没有新开和刷新页面,或者访客关闭了浏览器,则被计算为本次访问结束;
    • 独立访客(UV):1天内相同的访客多次访问您的网站只计算1个UV;
    • 独立IP(IP):指1天内使用不同IP地址的用户访问网站的数量。同一IP无论访问了几个页面,独立IP数均为1;
    *************** 当你发现自己的才华撑不起野心时,就请安静下来学习吧!***************
  • 相关阅读:
    事务创建函数
    实现Xshell断开连接情况下Linux命令继续执行
    MySQL UNION 操作符
    CentOS安装部署Mysql 5.7
    连接数据库
    @Results用法总结
    在Java中如何高效的判断数组中是否包含某个元素
    Java中的map集合顺序如何与添加顺序一样
    instanceof的用法
    枚举
  • 原文地址:https://www.cnblogs.com/lvzhenjiang/p/14198983.html
Copyright © 2011-2022 走看看