awk
awk
grep和egrep:文本过滤
sed:流编辑器,实现编辑的
awk:文本报告生成器,实现格式化文本输出
awk是一种优良的文本处理工具,
linux和unix环境中现有的功能最强大的数据处理引擎之一
awk是三个人的姓的缩写
在linux下的awk实际上是gawk(gun awk)
[root@localhost ~]# which awk
/usr/bin/awk
[root@localhost ~]# ll /usr/bin/awk
lrwxrwxrwx. 1 root root 4 Oct 24 01:54 /usr/bin/awk -> gawk
语法格式
任何awk语句都是由模式和动作组成,一个awk脚本可以有多个语句
模式决定动作语句的触发条件和触发时间
-
模式
- 正则表达式 /root/ 匹配含有root的行
- 关系表达式 < > && || + *
- 匹配表达式 ~ !~
-
动作
- 变量 命令 内置函数 流控制语句
语法结构
awk [options]
'BEGIN{ print 'start' }
pattern{ commands }
END{ print 'end' }' file
BEGIN和END是awk的关键字,因此必须大写
BEGIN语句设置计数和打印头部信息,在任何动作之前进行
END语句输出统计结果,在完成动作之后执行
awk工作的三个步骤
1读,从文件,管道,或标准输入中读入一行然后把它放到内存中
2执行 对每一行数据,根据awk命令按顺序执行,默认情况是处理每一行数据,也可以指定模式
3重复 一种重复上述两个过程直到文件结束
awk支持两种不同类型的变量,内建变量和自定义变量
内置变量 | 描述 |
---|---|
$n | 当前记录的第n个字段,比如:$1表示第一个字段,$2表示第二个字段 |
$0 | 这个变量包含执行过程中当前行的文本内容 |
FILENAME | 当前输入文件的名 |
FS | 字段分隔符(默认是空格) |
NF | 表示字段数,在执行过程中对应于当前的字段数,NF:列的个数 |
FNR | 各文件分别计数的行号 |
NR | 表示记录数,在执行过程中对应于当前的行号 |
OFS | 输出字段分隔符,(默认值是一个空格) |
ORS | 输出记录分隔符(默认值是一个换行符) |
RS | 记录分隔符(默认值是一个换行符) |
常用的命令选项
- -F fs指定分隔符
- -v 赋值一个用户自定义变量
- -f 指定脚本文件,从脚本中读取awk命令
分隔符的使用
[root@localhost ~]# echo AA BB CC DD | awk '{print $2}'
BB
[root@localhost ~]# echo AA,BB,CC,DD | awk -F "," '{print $2}'
BB
[root@localhost ~]# echo "AA|BB|CC|DD" | awk -F "|" '{print $2}'
BB
默认分隔符是空格,通过-F指定分隔符
[root@localhost ~]# echo "aergdfsshbtryhgdfshrts" | awk -Fbt '{print $1}'
aergdfssh
[root@localhost ~]# echo "aergdfsshbtryhgdfshrts" | awk 'BEGIN{FS="bt"} {print $1}'
aergdfssh
过滤出当前系统的IP地址
[root@VM_0_7_centos ~]# ifconfig eth0 | grep netmask
inet 172.17.0.7 netmask 255.255.240.0 broadcast 172.17.15.255
[root@VM_0_7_centos ~]# ifconfig eth0 | grep netmask | awk '{print $2}'
172.17.0.7
指定多个分隔符
[root@localhost ~]# echo "aergdfsshbtryhgdfshrts" | awk -F[fb] '{print $1}'
aergd
[root@localhost ~]# echo "aergdfsshbtryhgdfshrts" | awk -F[fb] '{print $2}'
ssh
关系运算符的使用
[root@VM_0_7_centos ~]# cat a.txt
4 5 6 7 8
5 6 7 8 9
6 7 8 9 10
[root@VM_0_7_centos ~]# awk '{print $1+10}' a.txt
14
15
16
取最后一个值
[root@VM_0_7_centos ~]# echo "one two three four" | awk '{print $4}'
four
[root@VM_0_7_centos ~]# echo "one two three four" | awk '{print $NF}'
four
取倒数第二个值
[root@VM_0_7_centos ~]# echo "one two three four" | awk '{print $(NF-1)}'
three
取第二个值
[root@VM_0_7_centos ~]# echo "one two three four" | awk '{print $(NF/2)}'
two
统计当前内存的使用率
[root@localhost ~]# cat frees.sh
#! /bin/bash
i=`free -m | grep Mem | awk '{print (($3/$2)*100)"%"}'`
echo -e "内存使用百分百: \e[31m$i \e[0m"
[root@localhost ~]# bash frees.sh
内存使用百分百: 16.2551%
输出多个值
打印出passwd文件中用户UID小于10的用户名和它登录所使用的shell
在两个字段中添加符号
[root@VM_0_7_centos ~]# awk -F ':' '$3<10{print $1 "<==>" $NF}' /etc/passwd
root<==>/bin/bash
bin<==>/sbin/nologin
daemon<==>/sbin/nologin
...
在两个字段中添加制表符
[root@VM_0_7_centos ~]# awk -F ':' '$3<10{print $1 "\t" $NF}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
...
输出多个列时,可以加','分隔
[root@VM_0_7_centos ~]# awk -F ':' '$3<10{print $1,$NF}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
打印出系统中UID小于10且登录shell是/bin/bash的用户
[root@VM_0_7_centos ~]# awk -F ':' '$3<10 && $NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash
NR和FNR
输出行号大于等于3且小于6 的行
[root@localhost ~]# awk -F: '(NR>=3 && NR<6){print NR,$0}' /etc/passwd
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
通过NR行号获取IP地址
[root@localhost ~]# ip addr | awk 'NR==9{print $2}'
192.168.0.234/24
NR和FNR的区别
[root@VM_0_7_centos ~]# awk '{print NR"\t" $1}' /etc/hostname /etc/hostname
1 VM_0_7_centos
2 VM_0_7_centos
[root@VM_0_7_centos ~]# awk '{print FNR"\t" $1}' /etc/hostname /etc/hostname
1 VM_0_7_centos
1 VM_0_7_centos
对于NR来说,在读取多个文件时,NR是一直加的
对于FNR来说,在读取多个文件时,会从1开始重新计算的
去除输出中的首行提示信息(grep,sed,awk)
[root@VM_0_7_centos ~]# route -n | grep -v ^Kernel
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0
172.17.0.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
[root@VM_0_7_centos ~]# route -n | sed 1d
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0
172.17.0.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
[root@VM_0_7_centos ~]# route -n | awk '(NR!=1){print $0}'
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0
172.17.0.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
正则表达式
使用awk查找出包含root字符的行,三种方法
[root@VM_0_7_centos ~]# awk -F: '/root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@VM_0_7_centos ~]# awk -F: '/root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@VM_0_7_centos ~]# awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
打印以root开头的行
[root@localhost ~]# awk -F: '/^root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
取出以bash结尾的行
[root@VM_0_7_centos ~]# awk -F: '/bash$/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
xue1:x:1000:1000::/home/xue1:/bin/bash
xue2:x:1001:1001::/home/xue2:/bin/bash
取出行中没有root的行
[root@VM_0_7_centos ~]# awk -F: '!/root/{print $0}' /etc/passwd
条件表达式
表达式?if-true:if-false
问号前面是条件,如果条件为真执行if-true
为假执行if-false
如果passwd中UID小于等于10,则给变量USER赋值为aaa,否则赋值为bbb
[root@VM_0_7_centos ~]# awk -F: '{$3<10? USER="aaa":USER="bbb";print $1,USER}' /etc/passwd
root aaa
bin aaa
...
nginx bbb
xue1 bbb
xue2 bbb
如果UID小于10,则输出user=>用户名,否则输出pass=>用户名
[root@VM_0_7_centos ~]# awk -F: '{if($3<10){print "user=>"$1} else{print "pass=>"$1}}' /etc/passwd
user=>root
user=>bin
...
pass=>nginx
pass=>xue1
pass=>xue2
- ~ 匹配
- !~ 不匹配
查出UID小于等于5且包括bin/bash的行
[root@VM_0_7_centos ~]# awk -F: '{if($3<=5 && $NF ~ "/bin/bash"){print $1,$NF}}' /etc/passwd
root /bin/bash
引用变量
用-v指定 var=value 变量名区分大小写
在程序中直接定义
在awk中,使用变量不用加$符号
[root@VM_0_7_centos ~]# var='test'
[root@VM_0_7_centos ~]# awk 'BEGIN{print "'$var'"}'
test
printf格式化输出
格式printf "format",item1,item2...
format使用注意事项
与print命令的最大不同是,printf需要指定format样式
format用于指定后面的每个item的输出格式
printf语句不会自动打印换行符 \n
format格式的指示符都以%开头,后跟一个字符
format样式
- %c 显示字符的ACSII码
- %d,%i 十进制整数
- %f 显示浮点数
- %s 显示字符串
- %% 显示%自身
输出passwd文件中的第一列内容,输出时不会换行
[root@VM_0_7_centos ~]# awk -F: '{printf "%s--",$1}' /etc/passwd
root--bin--daemon--adm--lp--sync--shutdown
...
换行输出
[root@VM_0_7_centos ~]# awk -F: '{printf "%s\n",$1}' /etc/passwd
root
bin
daemon
输出用户名,并在用户名前加字符串'USERNAME'
[root@VM_0_7_centos ~]# awk -F: '{printf "USERNAME: %s\n",$1}' /etc/passwd
USERNAME: root
USERNAME: bin
USERNAME: daemon
对$1和$NF都做格式化输出
[root@VM_0_7_centos ~]# awk -F: '{printf "%s--%s\n",$1,$NF}' /etc/passwd
root--/bin/bash
bin--/sbin/nologin
daemon--/sbin/nologin
awk修饰符
- N 显示宽度
-
- 左对齐
一个字母占一个宽度,默认是右对齐
显示时用10个字符串右对齐显示
[root@VM_0_7_centos ~]# awk -F: '{printf "%s--%s\n",$1,$NF}' /etc/passwd
root--/bin/bash
bin--/sbin/nologin
daemon--/sbin/nologin
使用10个宽度,左对齐显示
[root@VM_0_7_centos ~]# awk -F: '{printf "%-10s\n",$1}' /etc/passwd
root
bin
daemon
第一列使用15个字符宽度左对齐输出,最后一列使用15个字符宽度右对齐输出
[root@VM_0_7_centos ~]# awk -F: '{printf "%-15s%15s\n",$1,$NF}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
[root@VM_0_7_centos ~]# cat test.awk
BEGIN{
print "UserID\t\t\t\tShell"
print "---------------------------------------"
FS=":"
}
$3<10 && $NF=="/bin/bash"{
printf "%-20s%20s\n",$1,$NF
}
END{
print "---------------------------------------"
}
[root@VM_0_7_centos ~]# awk -f test.awk /etc/passwd
UserID Shell
---------------------------------------
root /bin/bash
---------------------------------------