AI智能
改变未来

14.Shell之awk

小破站学习笔记

awk介绍

1.awk是一种编程语言,主要用于Linux/unix下对文本和数据进行处理,是Linux/unix下的一个工具。数据可以来源标准输入,一个或多个文件,或者是其他命令的输出2.awk的处理文本和数据的方式:逐行扫描文件,默认从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作3.awk分别代表作者姓氏 的第一个字母4.gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展5.Linux用到的就是gwak

awk能干啥

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

awk的使用方式

  • 命令行模式
awk 选项 \'命令部分\' 文件名特别说明:引用shell变量需要双引号引起
  • 常用选项
-F 定义字段分隔符-v 定义变量并赋值
  • 命令部分说明
正则表达式 地址定位\'/root/{awk语句}\'	sed:\'/root/p\'\'NR==1,NR==5{wak语句}\'	sed:\'1,5p\'\'/^root/,/^ftp/{wak语句}\'	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语句}\'
  • 脚本模式
脚本编写#!/bin/awk -f以下是wak引号里的命令清单,不需要用引号保护,多个命令分号隔开BEGIN{FS=\'\';\'\'}NR==1,NR==3{print $1\"\\t\"$NF}...脚本执行方法一awk -f awk.sh filenamesed -f sed.sh -i filename方法二./awk.sh filename./sed.sh filename

awk内部相关的变量

$0	当前处理行的所有记录$1,$2,$3.. 文件中每行以间隔符号分割的不同字段NF	当前记录的字段数(列数)$NF	最后一列FNR/NR	行号FS	定义间隔符OFS	定义输出字段分隔符,默认空格RS	输入记录分隔符,默认换行ORS	输出记录分割符,默认换行
awk \'print $0\' 1.txt打印所有行awk \'NR==1,NR==5\' 1.txtawk \'NR==1,NR==5{print $0}\' 1.txt打印1-5行awk \'NR==1||NR==5{print $0}\' 1.txt打印1或5行awk \'NR==3,NR==5{print $0}\' 1.txtawk \'NR>=3&&NR<=5{print $0}\' 1.txt打印3-5行awk -F: \'{print $1,$3}\'显示以:分割的第一列和第三列awk -F:\'print NF\'显示以:分割 一共多少列$(NF-1)倒数第二列awk -F: \'print $1,$(NF-1)\' 1.txt打印以:分割的第一列和倒数第二列awk -F: \'print $1,$(NF-1),$NF,NF\' 1.txt打印以:分割的第一列和倒数第二列和最后一列和总的列数awk \'/root/{print $0}\' 1.txtawk \'/root/\' 1.txt打印包含root的内容awk -F: \'/root/{print $1,$NF}\' 1.txt匹配root的哪一行在以分号隔开的第一列和最后一列awk \'NR==1,NR==5\' 1.txtawk \'NR==1,NR==5{print $0}\' 1.txt显示一到5行awk \'NR==1,NR==5;/^root/{print $0}\' 1.txt显示一到5行 匹配root 有点不理解awk -F: \'BEGIN{OFS=\"@@\"};{print $1,$NF}\' 1.txt以分号分割显示第一列和最后一列 输出内容以@@作为分隔符显示 默认是空格awk \'BEGIN{FS=\":\";OFS=\"@@\"};{print $1,$NF}\' 1.txt以分号分割显示第一列和最后一列 输出内容以@@作为分隔符显示awk \'BEGIN{FS=\":\"};{print $1\"********\"$NF}\' 1.txt以分号分割显示第一列和最后一列 输出内容以******作为分隔符显示awk \'BEGIN{RS=\"\\t\"};{print $1}\' 1.txt将制表符作为输入记录分隔符 读取处理

awk的工作原理

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

awk使用进阶

  • 格式化输出print和printf
print函数 类似echodate | awk \'{print \"Month:\"$2\"\\nYear:\"$NF}\'打印出月份 年 并换行显示printf函数 类似echo -nawf -F: \'{printf \"%-15s %-10s %-15s\\n\",$1,$2,$3}\' 1.txt3               837               6awf -F: \'{printf \"|%-15s |%-10s |%-15s|\\n\",$1,$2,$3}\' 1.txt%s 字符类型 %-20s左对齐20个字符%d 数值类型- 表示左对齐 默认右对齐printf 默认不会在行尾自动换行,加\\n
  • awk变量的定义
awk -v NUM=3 -F: \'{print NUM}\' 1.txt调用定义的变量时不用加$
  • awk中BEGIN…END使用
BEGIN 表示在程序开始前执行END 表示所有文件处理完执行用法 \'BEGIN{开始处理之前};{处理中};END{处理结束后}\'
awk -F: \'BEGIN{ print \"Login_shell\\t\\tLogin_home\\n*******************\"};{print $NF\"\\t\\t\"$(NF-1)};END{print \"**************\"}\' 1.txtawk \'BEGIN{ FS=\":\";print \"Login_shell\\t\\tLogin_home\\n*******************\"};{print $NF\"\\t\\t\"$(NF-1)};END{print \"**************\"}\' 1.txtLogin_shell             Login_home*********************/bin/bash               /root/sbin/nologin           /bin/sbin/nologin           /sbin/sbin/nologin           /var/adm/sbin/nologin           /var/spool/lpd**********************awk -F: \'BEGIN{OFS=\"\\t\\t\";print\"u_name\\t\\tth_dir\\t\\tshell\\n****************************************\"}\';{print \"%-20s %-20s %-20s\\n\",$1,$(NF-1),$NF};END{print \"****************************************\"}\' 1.txtawk -F: \'BEGIN{OFS=\"\\t\\t\";printf \"%-20s %-20s %-20s\\n**********************************************************\\n\",\"u_name\",\"th_dir\",\"shell\"};{printf \"%-20s %-20s %-20s\\n\",$1,$(NF-1),$NF};END{print \"****************************************\"}\' 1.txtu_name               th_dir               shell**********************************************************root                 /root                /bin/bashbin                  /bin                 /sbin/nologindaemon               /sbin                /sbin/nologinadm                  /var/adm             /sbin/nologinlp                   /var/spool/lpd       /sbin/nologin*********************************************************
  • awk和正则的综合使用
==	等于!=	不等于>	大于<	小于>=	大于等于<=	小于等于~	匹配!~	不匹配!	逻辑非&&	逻辑与||	逻辑或
从第一行开始匹配到lp开头的行awk -F: \'NR==1,/^lp/{print $0}\' 1.txt从第一行到第五行awk -F: \'NR==1,NR==5{print $0}\' 1.txt从以lp开头的行匹配到第十行awk -F: \'/^lp/,NR==10{print $0}\' 1.txt从以root开头的行匹配到以lp开头的行awk -F: \'/^root/,/^lp/{print $0}\' 1.txt打印以root开头或者以lp开头的行awk -F: \'/^root/ || /^lp/{print $0}\' 1.txtawk -F: \'/^root/;/^lp/{print $0}\' 1.txt打印5-10行awk -F: \'NR<11 && NR>4{print $0}\' 1.txt打印30-39行以bash结尾的内容awk \'NR>=30 && NR<=39 && $0 ~ /bash$/{print $0}\' 1.txtawk \'NR>=30 && NR<=39 && /bash$/{print $0}\' 1.txt打印1-3行不以bash结尾的内容awk \'NR>=1 && NR<=3 && $0 !~ /bash$/{print $0}\' 1.txt; 2个动作同时|| 逻辑或awk 打印ip地址ifconfig eth0|awk \'NR>1 {print $2}\' | awk -F\':\' \'NR<2 {print $2}\'多种方法ifconfig eth0|grep Bcast|awk -F\'[: ]+\' \'{print  $4}\'[: ]+ 前导字符:或者 空格 出现一次或者多次ifconfig eth0|awk -F\'[: ]+\' \'/inet addr/{print  $4RS$6RS$8}\'RS 默认换行
  • awk的脚本编程
  • if结构
正则awk 选项 \'正则,地址定位{awk语句}\' 文件名判断第三列大于500小于60000才输出awk -F: \'{if($3>=500 && $3<=60000){print $1,$3} }\' 1.txt查寻管理员awk -F: \'{if($3==0){print $1\"是管理员\"}}\' 1.txt判断当前用户是不是管理员awk \'BEGIN{if($(id -u)==0){print \"is admin\"]}\'
  • if…else结构
格式{if(  ){  }else{  }}判断用户是不是普通用户awk -F: \'{if($3>=500 && $3 != 65534){print $1\"是普通用户\"}else{print $1\"不是普通用户\"}}\'awk -F: \'{if($(id -u) >= 500 -a $(id -u) != 65534){print $1\"是普通用户\"}else{print $1\"不是普通用户\"}}\'
  • if…esif…结构
if...else if....else格式{if(){} else if(){} else if(){}else{}}awk -F: \'{ if($3==0){i++}else if($3>=1 && $3<=499 || $3==65534) {j++} else {k++}};END{print \"管理员个数:\"i\\n\"系统用户个数为\"j\\n\"普通用户的个数为:\"k}\'
  • for循环
for ((i=1;i<=5;i++));do echo $i;done打印1-5awk \'BEGIN {for (i=1;i<=5;i++){print i}}\'打印1-10的奇数awk \'BEGIN {for (i=1;i<=10;i+=2){print i}}\'计算1-10的奇数和awk \'BEGIN{sum=0;for(i=1;i<=10;i+=2) sum=sum+i;{print sum}}\'for ((i=1;i<=10;i+=2));do echo $i;done|awk \'{sum+=$0};END{print sum}\'
  • while循环
打印1-5i=1;while(($i<=5));do echo $i;let i++;doneawk \'BEGIN{i=1;while(i<=5){print i;i++}}\'计算1-10的奇数和awk \'BEGIN{sum=0;i=1;while(i<=10) {sum=sum+i;i+=2};{print sum}}\'awk \'BEGIN{i=1;while(i<=5){print i;i++}}\'|awk \'{sum+=$0};END{print sum}\'
  • 嵌套循环
#!/bin/bashfor ((y=1;y<=5;y++))dofor ((x=1;x<=$y;x++))doecho -n $xdoneechodoneawk \'BEGIN{for(y=1;y<=5;y++){for(x=1;x<=y;x++){printf x};{print}}}\'112123123412345
  • awk算术运算
+ - * / % ^可以在模式中执行运算awk 都将按浮点数方式执行算术运算awk \'BEGIN{print 1+1}\'awk \'BEGIN{print 1*1}\'awk \'BEGIN{print 2**3}\'awk \'BEGIN{print 2/3}\'

awk统计案例

  • 统计系统中各种类型的shell
awk -F: \'{shell[$NF]++};END{for (i inshells) {print i,shells[i]}}\'
  • 统计网站访问状态
ss -an|grep :80|awk \'{states[$2]++};END{for (i in states){print i,states[i]}}\'|sort -k2 -rn
  • 统计网站访问的每个ip数量
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
  • 统计网站日志中的PV量 网站浏览量
grep \'27/Jul/2020\' mysqladmin.cc-access_log | wc -l统计日志中某一天的PV量grep \'27/Jul/2020\' mysqladmin.cc-access_log | awk \'{ips[$1]++};END{for(i in ips){print i,ips[i]}}\' | sort -k2 -rn | headgrep \'27/Jul/2020\' mysqladmin.cc-access_log | awk \'{ips[$1]++};END{for(i in ips){print i,ips[i]}}\' |awk \'$2>100\'| sort -k2 -rn | head统计日志中某一天不同IP的访问量
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 14.Shell之awk