awk的基本用法
Posted Richard_Chiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了awk的基本用法相关的知识,希望对你有一定的参考价值。
awk的基本用法
工作原理
逐行读取文本,默认以空格或tab键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。
sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个"字段"然后再进行处理。awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。在使用awk命令的过程中,可以使用逻辑操作符"&&"表示"与"、"||"表示"或"、"!"表示"非";还可以进行简单的数学运算
&& | \\ | \\ | ! | + | - | * | / | % | ^ | |
---|---|---|---|---|---|---|---|---|---|---|
与 | 或 | 非 | 加 | 减 | 乘 | 除 | 取余 | 乘方 |
命令格式
awk 选项 模式或条件 操作 文件1 文件2 ……
awk -f 脚本文件 文件1 文件2 ……
awk常见的内建变量(可直接用)如下所示:
FS:列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与"-F"作用相同
RS:行分隔符。awk从文件上读取资料时,将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录,以进行处理。预设值是\\n
NF:当前处理的行的字段个数。
NR:当前处理的行的行号(序数)。
$0:当前处理的行的整行内容。
$n:当前处理行的第n个字段(第n列)。
FILENAME:被处理的文件名。
按字段输出文本
#输出第一到第三行
[root@localhost ~]# awk NR==1,NR==3 print $0 one.sh
one
two
three
[root@localhost ~]# awk (NR>=1)&&(NR<=3) print $0 one.sh
one
two
three
#只输出第一行第三行
[root@localhost ~]# awk NR==1||NR==3 print $0 one.sh
one
three
#求奇数行
[root@localhost ~]# awk (NR%2)==1 print one.sh
one
three
five
seven
nine
eleven
[root@localhost ~]# for b in $(cat one.sh)
> do
> if [ $[a%2] -eq 1 ];then
> echo $b
> fi
> let a++
> done
one
three
five
seven
nine
eleven
#求偶数行
[root@localhost ~]# awk (NR%2)==0 print one.sh
two
four
six
eight
ten
twelve
#通过字符来查找以t为开头的行文本内容
[root@localhost ~]# awk /^t/ print one.sh
two
three
ten
twelve
#通过字符来查找/etc/passwd文件中以bash为结尾的行
[root@localhost ~]# awk /bash$/ print /etc/passwd
root:x:0:0:root:/root:/bin/bash
linux-5:x:1000:1000:Linux-5:/home/linux-5:/bin/bash
#awk查找/etc/passwd文件中所有以/bin/bash结尾的行,然后执行x+1的操作从而统计出来
BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的操作;
awk再处理指定的文本,之后再执行END模式中指定的操作;
END语句块中,往往会放入打印结果等语句
[root@localhost ~]# awk BEGIN x=0;/\\/bin\\/bash$/x++;END print x /etc/passwd
2
#统计以/bin/bash结尾的行数,等同于grep -c "/bin/bash$" /etc/passwd
awk NR==1 print $1 one.sh #输出文本中第一行第一列的内容
awk NR==1 print NF one.sh #输出多少列
awk NR==1 print $NF one.sh #输出最后一列内容
指定列操作符:
#输出UID号大于等于1000的行号
awk -F ":" $3>=1000 print $1,$3 /etc/passwd
#输出UID号不小于1000的行号
awk -F ":" !($3<1000) print $1,$3 /etc/passwd
或
awk BEGIN FS=":";if($3>=1000)print $1,$3 /etc/passwd
awk -F ":" max=($3>=$4)?$3:$4;print max /etc/passwd
#($3>$4)?$3:$4;三元运算符,如果第3个字段的值大于等于第4个字段的值,则把第3个字段的值赋给max,否则第4个字段的值赋给max
#打印出所有内容并且输出行号
[root@localhost ~]# awk -F: print NR,$0 one.sh
1 one
2 two
3 three
4 four
5 five
6 six
7 seven
8 eight
9 nine
10 ten
11 eleven
12 twelve
#打印出/etc/passwd中所有带有root的行数并且输出行号,输出每行内容和行号,每处理完一条记录,NR值加1
[root@localhost ~]# awk -F: /root/print NR,$0 /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
10 operator:x:11:0:operator:/root:/sbin/nologin
#打印出带有/etc/passwd文件中带有bash的用户名,输出以冒号分隔且第7个字段中包含/bash的行的第1个字段
[root@localhost ~]# awk -F: $7~"bash"print NR,$1 /etc/passwd
1 root
41 linux-5
#输出第1个字段中包含root且有7个字段的行的第1、2个字段
[root@localhost ~]# awk -F ":" ($1~"root")&&(NF==7) print $1,$2 /etc/passwd
root x
#输出第7个字段既不为/bin/bash,也不为/sbin/nologin的所有行
[root@localhost ~]# awk -F: ($NF!="/bin/bash")&&($7!="/sbin/nologin") print /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
通过管道、双引号调用Shell命令
#统计以冒号分隔的文本段落数,END语块中,往往会放入打印结果等语句
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost ~]# echo $PATH | awk BEGIN RS=":"; print NR
1
2
3
4
5
[root@localhost ~]# echo $PATH | awk BEGIN RS=":"; END print NR
5
#调用wc -l命令统计使用bash的用户个数,等同于grep -c "/bin/bash$" /etc/passwd
[root@localhost ~]# awk -F: /bash$/ print | "wc -l" /etc/passwd
2
相当于:
[root@localhost ~]# awk -F: /bash$/ print /etc/passwd | wc -l
2
#查看当前内存使用百分比
[root@localhost ~]# free | awk /Mem:/print $3/$2*100"%"
14.866%
取整数值
[root@localhost ~]# free | awk /Mem:/print int($3/$2*100)"%"
14%
#查看cup的使用率空闲率,top -b -n 1用于获取一次静态的top结果,方便数据的截取
[root@localhost ~]# top -b -n 1 | awk -F, /Cpu/print $4 | awk print $1
100.0
date命令用法
#显示年月日
[root@localhost ~]# date +"%Y/%m/%d %H:%M:%S"
2021/12/27 09:40:40
#这个月的第一天
[root@localhost ~]# date +%Y%m01
20211201
#上个月的最后一天
[root@localhost ~]# date -d "$(date +%Y%m01) -1 day" +"%Y%m%d"
20211130
[root@localhost ~]# date -d "$(date +%Y%m01) -1 day" +"%F"
2021-11-30
#这个月的最后一天
[root@localhost ~]# date -d "$(date -d "1 month" +%Y%m01) -1 day" +%F
2021-12-31
#显示上次系统重启时间,等同于uptime;second ago为显示多少秒前的时间
[root@localhost ~]# date -d "$(cat /proc/uptime | awk -F. print $1) second ago" +"%F %H:%M:%S"
2021-12-27 08:34:51
#调用w命令,并用来统计在线用户数
[root@localhost ~]# awk BEGIN n=0 ; while ("w" | getline) n++ ; print n-2
1
#调用hostname并输出当前主机名
[root@localhost ~]# awk BEGIN "hostname" | getline ; print $0
localhost.localdomain
使用getline命令会把相应的结果获取并且把值赋给后面的"$0"
getline命令
#获取偶数行
[root@localhost ~]# seq 10 | awk getline; print $0
#awk先读取第一行内容,然后getline会换一行然后通过print $0打印出来
2
4
6
8
10
#获取奇数行
[root@localhost ~]# seq 10 | awk print $0; getline
#awk读取第一行内容,通过print $0打印出来,getline会换一行但是后面没有打印操作所以不进行操作
1
3
5
7
9
当getline左右无重定向符“<”或“|”时,awk首先读取到了第一行,就是1,然后getline, 就得到了1下面的第二行,就是2,因为getline之后,awk会改变对应的NF,NR, FNR和$0等内部变量,所以此时的$0的值就不再是1,而是2了,然后将它打印出来。
当getline左右有重定向符“<”或“|”时,getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。
$0表示整行内容
NF:当前处理的行的字段个数。
NR:当前处理的行的行号(序数)
FNR:表示awk当前读取的记录数
OFS指定分隔符
[root@localhost ~]# echo "A B C D" | awk BEGINOFS="|";print $1 $2 $3 $4
ABCD
[root@localhost ~]# echo "A B C D" | awk BEGINOFS="|";print $1,$2,$3,$4
A|B|C|D
[root@localhost ~]# echo "A B C D" | awk BEGINOFS="|";$1=$1;print $0
A|B|C|D
$1=$1是用来激活$0的重新赋值,也就是说
字段$1...和字段数NF的改变会促使awk重新计算$0的值,通常是在改变OFS后而需要输出$0时这样做
OFS:指定awk输出的列分隔符
awk的高级结合操作
[root@localhost ~]# cat test.txt
aaa
aaa
bbb
ccc
aaa
bbb
aaa
#awk中可以把数组定义成字符串
[root@localhost ~]# awk BEGINa[0]=10; a[1]=20;print a[1]
20
[root@localhost ~]# awk BEGINa[0]=10; a[1]=20;print a[0]
10
[root@localhost ~]# awk BEGINa["abc"]=10; a["def"]=20;print a["abc"]
10
[root@localhost ~]# awk BEGINa["abc"]=10; a["def"]=20;print a["def"]
20
#但是Linux中不可以用字符串输出
[root@localhost ~]# arr["abc"]=10
[root@localhost ~]# arr["def"]=20
[root@localhost ~]# echo $arr[@]
20
[root@localhost ~]# awk BEGINa[0]=10; a[1]=20; a[2]=30; for(i in a)print i,a[i]
0 10
1 20
2 30
BEGIN模式中的命令执行一次
awk中的数组的下标和元素的值都可以是数字也可以是字符串,字符串需要用双引号括起来
awk数组的数组名保存的是下标的列表,相对应的元素的值使用数组名[下标]
来表示
#达到统计效果
[root@localhost ~]# awk a[$1]++; END for(i in a)print i,a[i] test.txt
aaa 4
ccc 1
bbb 2
#再进行相应排序
[root@localhost ~]# awk a[$1]++; END for(i in a)print i,a[i] test.txt | sort -t -k2 -nr
aaa 4
bbb 2
ccc 1
总结:
首先a[$1]++; $1代表的是文件的第一列内容,并且awk会逐行读取文件中的内容,a[$1]初始值为0,当awk匹配到一行相同内容后就会自增加1,也就是说 a[$1] 的值取决于$1在文件中的此列中出现的次数,而$1的值都保存在数组a中;
END for(i in a)print i,a[i] END模式的操作是在awk处理完文件内容后再执行的操作;
for 循环中的变量 i 用来遍历获取数组a的值(也就是说是$1的值);print i 相当于把$1列中不同的值进行去重后输出;a[i]相当于把$1列中不同的值对应出现的次数进行输出。
#过滤出密码输错误3次的IP
[root@localhost ~]# awk /Failed passwd/ip[$11]++; END for(i in ip)print i,ip[i] /var/log/secure-20211227 | awk $2>3print $1
监控脚本(监控系统各项指标、监控服务状态、硬件的信息、安全的监控)
cpu负载,内存容量,硬盘空间,网卡流量,安装的软件包数量,账户数量,当前登录的账户数量,进程数量,输错密码的主机
uptime,free -m,df -h,ifconfig ens33,rpm -qa | wc -l,/etc/passwd,who,ps aux,/var/log/secure
ip=`ifconfig ens33 | awk /inet /print $2`
echo "本地IP地址是:"$ip
cpu= `uptime | awk print $NF`
#awk中NF为当前行的列数,$NF是最后一列
echo"本机CPU最近15分钟的负载是:"$cpu
net_in=`ifconfig ens33 | awk /RX p/print $5`
echo "入站网卡流量为:"$net_in
net_out=`ifconfig ens33 | awk /TX p/print $5`
echo "出站网卡流量为:"$net_out
mem=`free -m | awk /^Mem/print $4)`
echo "内存剩余容量为:" $mem
disk=`df -h | awk /sda1/print $4`
echo "根分区剩余容量为:"$disk
user=`cat /etc/passwd |wC -l`
echo "本地账户数量为:"$user
login=`who | wc -l`
echo "当前登陆计算机的账户数量为:"$login
process=`ps aux | wc -l`
echo "当前计算机启动的进程数量为: "$process
soft=`rpm-qa | wc -l`
echo "当前计算机已安装的软件数量为:"$soft
系统初始化脚本(创建目录,账户,安装软件吧,设置权限,修改内核参数,防火墙,selinux)
一键部署脚本(源码编译安装的脚本)
备份脚本(自动备份数据库,备份网址的日志数据,配置文件)
日志分析脚本(分析日志的数据,汇总统计相关信息,PV(网页的点击量),UV(访问的客户端数量))
以上是关于awk的基本用法的主要内容,如果未能解决你的问题,请参考以下文章