awk基本用法
awk 是一种编程语言,用于在 linux/unix 下对文本和数据进行处理。
awk 数据可以来自标准输入、一个或多个文件,或其它命令的输出。
awk 通常是配合脚本进行使用, 是一个强大的文本处理工具。
awk基本知识
awk 的两种形式语法格式
awk [options] 'commands' filenames
awk [options] -f awk-script-file filenames
options
-F 定义输入字段分隔符,默认的分隔符是空格或tab键(就是改变内部变量 FS,FS 来确定字段分隔符)
OFS 是另一个内部变量,用来定义输出字段分隔符的。比如 $1,$3 之间有个逗号,之后输出内容之间变为空格,是因为 OFS 默认为空格
command
BEGIN{} {} END{}
行处理前 行处理 行处理后
awk命令格式
## awk 匹配文件带root的行
[root@Shell ~]# awk '/root/' /etc/passwd
## awk 对文件行进行动作处理(以冒号为字段分隔符,打印第一个字段)
[root@Shell ~]# awk -F: '{print $1}' /etc/passwd
## awk 匹配文件 + 处理动作
[root@Shell ~]# awk -F ':' '/root/ {print $1,$3}' /etc/passwd
[root@Shell ~]# awk 'BEGIN{FS=":"} /root/{print $1,$3}' /etc/passwd
## awk 匹配结尾为 / 的行,第三个字段大于50000则打印第四个字段
[root@Shell ~]# df |awk '/\/$/ {if ($3>50000) print $4}'
awk内部变量
$0 所有内容
## 打印文件的所有内容
[root@Shell ~]# awk '{print $0}' /etc/passwd
NR 控制输入的总行数
## 打印文件行号
[root@Shell ~]# awk '{print NR,$0}' /etc/passwd
## 打印文件的前三行
[root@Shell ~]# awk 'NR<=3' /etc/passwd
FNR 记录输入文件行号(当读取多个文件FNR会从零开始计算行号,NR则不会)
## 打印文件行号
[root@Shell ~]# awk '{print FNR,$0}' /etc/passwd
## 打印第十行内容
[root@Shell ~]# awk 'NR==10{print $0}' /etc/passwd
NF 记录行的最后一分段内容
## 打印每一行最后一个分段
[root@Shell ~]# awk -F ":" '{print $NF}' /etc/passwd
## 打印文件总分段
[root@Shell ~]# awk '{print NF,$0}' /etc/passwd
FS 指定字段分割符,默认空格
## 以冒号作为字段分隔符
[root@Shell ~]# awk -F: '/root/{print $1, $3}' /etc/passwd
[root@Shell ~]# awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd
## 以空格冒号 tab 作为字段分割
[root@Shell ~]# awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd
OFS 输出字段分隔符
## 以冒号为输出分隔符,匹配开始为root的行,输出一二三分段,输出分段之间以+++间隔
[root@Shell ~]# awk -F ':' 'BEGIN{OFS="+++"} /^root/{print $1,$2,$3}' /etc/passwd
root+++x+++0
RS 输入记录分隔符,awk是根据 RS 来定位检索断点的。因为 RS 默认换行符(\n),所有awk默认是逐行来检索
## 提取下面三个域名
[root@Shell ~]# echo '<a href="www.songguoyou.com">宋国友</a><a href="www.baidu.com">百度</a><a>href="www.taobao.com">淘宝</a>' > link.txt
## 以 </a> 划分行
[root@Shell ~]# awk 'BEGIN{RS="</a>"}{print NR,$0}' link.txt
1 <a href="www.songguoyou.com">宋国友
2 <a href="www.baidu.com">百度
3 <a href="www.taobao.com">淘宝
4
## 用 NF>0 来排除空行(删除所有 NF=0 的分段)
[root@Shell ~]# awk 'BEGIN{RS="</a>"}NF>0{print NR,$0}' link.txt
1 <a href="www.songguoyou.com">宋国友
2 <a href="www.baidu.com">百度
3 <a href="www.taobao.com">淘宝
## 最后以双引号为分隔符打印第二个分段
[root@Shell ~]# awk 'BEGIN{RS="</a>"}NF>0{print $0}' link.txt |awk 'BEGIN{FS="\""}{print $2}'
www.songguoyou.com
www.baidu.com
www.taobao.com
ORS 输出记录分隔符,和RS原理一样,就是作用在输出上了
## 输出时候把所有换行符替换成 |
[root@Shell ~]# awk 'BEGIN{ORS="|"}{print $0}' /etc/sysconfig/network-scripts/ifcfg-eth0
TYPE=Ethernet|PROXY_METHOD=none|BROWSER_ONLY=no|BOOTPROTO=static|DEFROUTE=yes|IPV4_FAILURE_FATAL=no|IPV6INIT=yes|IPV6_AUTOCONF=yes|IPV6_DEFROUTE=yes|IPV6_FAILURE_FATAL=no|IPV6_ADDR_GEN_MODE=stable-privacy|NAME=ens33|UUID=34e475e4-12a1-4c0f-bdaa-68b467ea9c44|DEVICE=eth0|ONBOOT=yes|IPADDR=192.168.1.1|[root@Shell ~]#
print 格式化输出函数
[root@Shell ~]# date|awk -F '[ :]' '{print "当前时间:",$NF,"年",$2,"月",$3,"日""\n",$4,"小时",$5,"分",$6,"秒"}'
## printf 函数
[root@Shell ~]# awk -F: '{printf "%-15s %-10s %-15s\n", $1, $2, $3}' /etc/passwd
%c: 显示字符的ASCII码;
%d, %i: 显示十进制整数;
%e, %E: 科学计数法数值显示;
%f:显示为浮点数;
%g, %G:以科学计数法或浮点形式显示数值;
%s:显示字符串;
%u:无符号整数;
%%: 显示%自身;
占 15 字符
- 表示左对齐,默认是右对齐
printf 默认不会在行尾自动换行,加\n
awk模式动作
awk语句都由模式和动作组成。
模式部分决定动作语句何时触发及触发事件。
如果省略模式部分,动作将时刻保持执行状态。
模式可以是条件语句或复合语句或正则表达式
使用正则表达式
## 匹配不以a、b、c、d为开头字母的行
[root@Shell ~]# awk '!/^[a-d]/' /etc/passwd
## 匹配第五个分段为a字母开头并且nologin为结尾的行
[root@Shell ~]# awk -F: '$5~/^a/&&/nologin$/' /etc/passwd
使用比较表达式
比较表达式使用关系运算符对数字与字符串进行比较,只有当条件为真,才执行指定的动作
## uid 为 0 的列出来
[root@Shell ~]# awk -F ":" '$3==0' /etc/passwd
## uid 小于 10 的全部列出来
[root@Shell ~]# awk -F: '$3 < 10' /etc/passwd
## 用户登陆的 shell 等于 /bin/bash
[root@Shell ~]# awk -F: '$7 == "/bin/bash" ' /etc/passwd
## 第一列为 alice 的列出来
[root@Shell ~]# awk -F: '$1 == "alice" ' /etc/passwd
## 为 alice 的用户列出来
[root@Shell ~]# awk -F: '$1 ~ /alice/ ' /etc/passwd
## 磁盘使用率大于多少则,则打印可用的值
[root@Shell ~]# df |awk '/\/$/'|awk '$3>1000000 {print $4}'
运算表达式
## 第三个分段和第四个分段相加
[root@Shell ~]# awk -F: '{print $3 + $4}' /etc/passwd
## 显示所有普通用户
awk -F: 'BEGIN{OFS="--"} { if($3*10>=10000) {print $1,$3} }' /etc/passwd
逻辑操作符和复合模式
&&逻辑与 || 逻辑或 !逻辑非
## 匹配用户名为 root 并且 uid 小于 1 的行
[root@Shell ~]# awk -F: '$1~/root/ && $3<=1' /etc/passwd
## 匹配用户名为 root 或 uid 大于 1000
[root@Shell ~]# awk -F: '$1~/root/ || $3>=1000' /etc/passwd
awk条件判断
if语句格式:{ if(表达式){语句;语句;... }}
## 打印当前管理员用户名称
[root@Shell ~]# awk -F: '{ if($3==0){print $1,"is adminisitrator"} }' /etc/passwd
## 统计系统用户数量
[root@Shell ~]# awk -F: '{ if($3>0 && $3<1000){i++}} END {print i}' /etc/passwd
## 统计普通用户数量
[root@Shell ~]# awk -F: '{ if($3>1000){i++}} END {print i}' /etc/passwd
if...else 语句格式: {if(表达式){语句;语句;... }else{语句;语句;...}}
## 如果 uid 等于 0 则打印用户名,否则打印 shell 环境变量
[root@Shell ~]# awk -F: '{if($3==0){print $1} else {print $NF}}' /etc/passwd
## 打印管理员个数和系统用户个数
[root@Shell ~]# awk -F: '{if($3==0){count++} else{i++}} END{print " 管理员个数: "count ; print "系统用户数: "i}' /etc/passwd
{if(表达式 1){语句;语句;... }else if(表达式 2){语句;语句;. .. }else{语句;语句;... }}
## 统计管理员、系统用户和普通用户的个数
[root@Shell ~]# awk -F: '{ if($3==0){i++} else if($3>0 && $3<1000){j++} else if($3>1000) {k++}} END {print "管理员个数"i; print "系统用户个数" j; print "普通用户个数"k }' /etc/passwd
awk循环语句
while循环
while(表达式){语句}
## 计算从1累加到100的值
[root@Shell ~]# awk 'BEGIN{test=100;num=0;while(i<=test){num+=i; i++;}print num;}'
for循环
for(初始表达式;终止条件;步长表达式){语句}
## 计算从1累加到100的值
[root@Shell ~]# awk 'BEGIN{test=0;for(i=0;i<=100;i++){test+=i;}print test;}'
do-while循环
do{语句}while(条件判断语句)
## 计算从1累加到100的值
[root@Shell ~]# awk 'BEGIN{test=0;i=0;do{test+=i;i++}while(i<=100)print test;}'
awk数组
[root@Shell ~]# awk -F: '{username[i++]=$1} END{print username[1]}' /etc/passwd
按索引遍历
## 遍历所有用户并打印
[root@Shell ~]# awk -F: '{username[j++]=$1}END{for(i in username){print i,username[i]}}' /etc/passwd
## 统计 /etc/passwd 中各种类型 shell 的数量
[root@Shell ~]# awk -F: '{shells[$NF]++}END{for(i in shells){print i,shells[i]}}' /etc/passwd
## 网站访问状态统计
[root@Shell ~]# ss -an|awk '/:80/{tcp[$2]++}END{for(i in tcp){print i,tcp[i]}}'
## 统计当前访问的每个IP的数量
[root@Shell ~]# ss -an|awk -F ':' '/:80/{ips[$(NF-1)]++} END {for(i in ips){print i,ips[i]}}'