一、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' |
| '{print $0;print $1}' sed中:'p' |
| 'NR==5{print $0}' sed中:'5p' |
| 注:awk命令语句间用分号间隔 |
| 'BEGIN{awk语句};{处理中};END{awk语句}' |
| 'BEGIN{awk语句};{处理中}' |
| '{处理中};END{awk语句}' |
2.2 脚本模式使用
1)脚本编写
| #!/bin/awk -f 定义魔法字符 |
| 以下是awk引号里的命令清单,不要用引号保护命令,多个命令用分号间隔 |
| BEGIN{FS=":"} |
| NR==1,NR==3{print $1"\t"$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="\t"};print $1,$3}' |
RS |
输入记录分割符,默认换行 |
'BEGIN{RS="\t"};{print $0}' |
ORS |
输出记录分割符,默认换行 |
'BEGIN{ORS="\n\n"};{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="\t\t"};/^root/,/^lp/{print $1,$NF}' passwd |
| # awk -F: 'BEGIN{OFS="@@@"};/^root/,/^lp/{print $1,$NF}' passwd |
| |
| RS和ORS: |
| # awk 'BEGIN{RS="\t"};{print $0}' 1.txt |
| # awk 'BEGIN{ORS="\t"};{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 "\nYear: "$NF}' |
| # awk -F: '{print "username is: " $1 "\t uid is: "$3}' /etc/passwd |
| |
| printf函数 类似echo -n |
| |
| # awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}' /etc/passwd |
| # awk -F: '{printf "|%15s| %10s| %15s|\n", $1,$2,$3}' /etc/passwd |
| # awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd |
| |
| awk 'BEGIN{FS=":"};{printf "%-15s %-15s %-15s\n",$1,$6,$NF}' a.txt |
| |
| %s 字符类型 |
| %d 数值类型 |
| %-15s:字符类型,占15字符,并且左对齐 |
| - 表示左对齐,默认是右对齐 |
| printf默认不会在行尾自动换行,加\n |
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\t\tLogin_home\n*******************"};{print $NF"\t\t"$(NF-1)};END{print "************************"}' passwd |
| |
| awk 'BEGIN{ FS=":";print "Login_shell\tLogin_home\n*******************"};{print $NF"\t"$(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 "\n系统用户个数为:"j"\n普通用户的个数为:"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"\t"};print} }' |
| # awk 'BEGIN{for(y=1;y<=9;y++) { for(x=1;x<=y;x++) printf x"*"y"="x*y"\t";print} }' |
| # awk 'BEGIN{i=1;while(i<=9){for(j=1;j<=i;j++) {printf j"*"i"="j*i"\t"};print;i++ }}' |
| # awk 'BEGIN{for(i=1;i<=9;i++){j=1;while(j<=i) {printf j"*"i"="i*j"\t";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;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律