awk 报告生成器
linux中文本处理三剑客:
grep:文本过滤器,根据匹配模式,显示匹配到的行 egrep==grep -E
sed:流编辑器
awk:是个报告生成器,也是文本处理工具。从文本中抽取符合条件的数据并以特定的格式显示出来。linux中的awk,GNU-awk==gawk
语法结构:
awk [option] 'PATTERN{ACTION}' file1 file2...
PATTERN:模式;是指定的抽取文件数据的条件。
ACTION:要对匹配的数据进行处理的动作。
在awk中的行与列:
filed 字段(列)
record 记录(行)
awk的模式
awk 'PATTERN{action}' file...
PATTERN 模式
awk 'BEGIN{}{pattern}{ACTION}{END}' file1,file2...
BEGIN和END只输入或输出一次
其他的每次都要执行
例
1、regexp 正则表达式
[root@localhost ~]# awk -F: '/^ro/{print $1}' /etc/passwd 整条数据和ro比较
2、表达式
[root@localhost ~]# awk -F: '$3>500{print $1}' /etc/passwd
[root@localhost ~]# awk -F: '$1~/^a/{print $1}' /etc/passwd 字段一和a比较
(NF,取最后一个字段)
[root@localhost ~]# awk -F: '$NF~/bash$/{print $1}' /etc/passwd
root
redhat
a
haha
1
[root@localhost ~]# awk -F: '$NF~/bash$/ && $1~/^ro/{print $1}' /etc/passwd
root
3、指定范围
从模式一到模式二 (模式一,模式二)取得是一个范围
[root@localhost ~]# awk -F: '$3==0,$7~/nologin$/{print $1}' /etc/passwd
root
bin
[root@localhost ~]# awk -F: '$1~/^s/,$7~/nologin$/{print $1}' /etc/passwd
字段一以s开头,字段七以nologin结尾
4、BEGIN/END 特殊的模式
[root@localhost ~]# awk -F: '$3==0,$7~/bash$/{print $1}END{print "end"}' /etc/passwd
root
end
$0 打印全部字段
$1 只打印第一片的字段 默认分隔符为空格
$2 只打印第二片的字段
例1
[root@localhost ~]# cat a
hello
my
name
is
huahua
[root@localhost ~]# awk '{print $0}' a
hello
my
name
is
huahua
-F:指定输入分隔符
例2
[root@localhost ~]# awk -F: '{print $1,$2}' /etc/passwd //指定分隔符为符号
root x
bin x
daemon x
awk的变量
内置变量:
FS:field separator 读取文本时,所使用的分隔符,与-F一样 列分隔符
RS:record separator 输入文本信息所使用的行分隔符 行分隔符
OFS:output field separator 输出分隔符 列分隔符
ORS:output row separator 输出信息所使用的行分隔符 行分隔符
----------BEGIN可以指定多个选项,通过分号隔开
例3
[root@localhost ~]# awk -F: 'BEGIN{OFS="@"}{print $1,$2,$3}' /etc/passwd
root@x@0 //指定输出分隔符为@
bin@x@1
daemon@x@2
[root@localhost ~]# awk -F: 'BEGIN{OFS="@"}{ORS="<==>"}{print $1,$2,$3}' /etc/passwd
root@x@0<==>bin@x@1<==>daemon@x@2<==>a //行分隔符为“<==>”
[root@localhost ~]# cat b
haha:
hei$:
lala:123
[root@localhost ~]# awk 'BEGIN{RS=":"}{print $1}' b
haha
hei$
lala
123
FNR和NR(行号相关)
FNR表示该记录在其对应文件中的行号, NR表示该记录在整个input stream中的行号。
如果只有一个文件,两者是一样的。如果是多个文件,则每读取一个新的文件时,FNR都会被重置为1,而NR一直增加。
例4
[root@localhost ~]# awk '{print FNR,$0}' a b
1 hello
2 my
3 name
4 is
5 huahua
1 haha:
2 hei$:
3 lala:123
[root@localhost ~]# awk '{print NR,$0}' a b
1 hello
2 my
3 name
4 is
5 huahua
6 haha:
7 hei$:
8 lala:123
NF(列号相关)
NF:当前行一共有多少列,而非列号
$(NF-1) 取得是倒数第二个字段(列)
例5
[root@localhost ~]# cat b
haha a b
hei c
la
[root@localhost ~]# awk '{print NF}' b
3
2
1
[root@localhost ~]# awk '{print $(NF-1),$NF}' b //打印倒数第二列和最后一列
a b
hei c
la la
自定义变量:
gawk 变量名需要区分大小写
1、在脚本中赋值变量
awk 'BEGIN{var="hello world";print var}'
2、在命令行中赋值变量
awk -v var="hello world" 'BEGIN{print var}'
awk的数组
例
//打印数组a中的元素,里面存储的元素没有顺序
[root@localhost ~]# awk -F: 'BEGIN{a["mon"]=1;a["tus"]=2}END{for(i in a){print i,a[i]}}' /etc/passwd
tus 2
mon 1
//统计每一种用户登录的bash
[root@localhost ~]# awk -F: '{shell[$NF]++}END{for(i in shell)print i,shell[i]}' /etc/passwd
/bin/sync 1
/bin/bash 5
/sbin/nologin 44
/sbin/halt 1
/sbin/shutdown 1
//分类统计网络系统的状态信息
[root@localhost ~]# netstat -an | awk '/^tcp/{hosts[$6]++}END{for(i in hosts){print i,hosts[i]}}'
LISTEN 13
ESTABLISHED 3
ARGV 保存命令行本身字符串
ARGC awk的参数的个数
例6
[root@localhost ~]# cat b
haha a b
hei c
la
[root@localhost ~]# awk '{print $0;print ARGV[1]}' b
haha a b
b
hei c
b
la
b
[root@localhost ~]# awk '{print $0;print ARGV[0]}' b
haha a b
awk
hei c
awk
la
awk
END取最后面一个路径
FILENAME:awk所处理的文件的名称
ENVIRON:当前shell环境变量及其值的相关联数组
例7
[root@localhost ~]# awk 'END{print FILENAME}' /root/b /etc/passwd
/etc/passwd
[root@localhost ~]# awk '{print ENVIRON["HOME"]}' /root/b
/root
/root
/root
[root@localhost ~]# awk 'BEGIN{print ENVIRON["HOME"]}' /root/b
/root
//BEGIN语句只执行一遍
awk的输出
printf
默认不会打印换行\n
%c:显示字符的ASCII码
%d %i:十进制整数
%e %E:科学计数法
%f:显示浮点数
%s:显示字符串
%u:无符号整数
%%:显示%本身
修饰符:
N:显示的宽度
-:左对齐,默认是右对齐
+:显示数值符号
例8
[root@localhost ~]# awk -F: 'BEGIN{printf "%6s %25s\n","UID","USERNAME"}{printf "%6s %25s\n",$3,$1}' /etc/passwd
UID USERNAME
0 root
1 bin
2 daemon
右对齐输出系统中每个用户的UID
awk -F: '{printf "%5d\n",$3}' /etc/passwd
左对齐
awk -F: '{printf "%-5d\n",$3}' /etc/passwd
awk的操作符
1、算术操作符:
-X:负数
x^y:x的y次方
x**y:x的y次方
x*y:乘法
x/y
x+y
x-y
x%y:取余
2、数值操作符:
=:赋值
+=
-=
*=
/=
%=
^=
**=
++
--
3、布尔值:
x<y
x<=y
x>y
x>=y
x==y
x!=y
x~y:X是个字符串,Y是个匹配模式,若X被Y匹配到则为真 x~/^r/
x!~y
4、表达式之间的逻辑关系:
&&
||
!
5、条件表达式:
A=4
B=3
A>B? a is max:b is max
awk的操作(action)
1、if else语句
例9
//如果第三个字段为0输出admin,否则输出nomal
[root@localhost ~]# awk -F: '{if($3==0){print "admin"}else{print "nomal"}}' /etc/passwd
admin
nomal
nomal
//如果第一个字段以ro开头,就输出admin,否则输出nomal
[root@localhost ~]# awk -F: '{if($1~/^ro/){print "admin"}else{print "nomal"}}' /etc/passwd
admin
nomal
//count初值为0,统计/etc/passwd文件里第三个字段大于500的有多少个
[root@localhost ~]# awk -F: 'BEGIN{count=0}$3>500{count++}END{print count}' /etc/passwd
13
//也可以用如下方法给count赋值,结果不变
[root@localhost ~]# awk -F: -v count=0 '{if($3>500)count++}END{print count}' /etc/passwd
13
初始化脚本变量一般放在begin里面,-v一般引用定义的变量
2、while语句
while(condition){语句1,语句2...}
例10
//length是内置函数;从字段一到最后一个字段,如果哪个字段长度大于等于4,输出该字段
[root@localhost ~]# awk -F: '{i=1;while(i<=NF){if(length($i)>=4){print $i};i++}}' /etc/passwd
root
root
/root
/bin/bash
do while语句 至少执行一次
while语句 可能一次都不执行
3、for循环
例11
//输出第一到第三个字段
[root@localhost ~]# awk -F: '{for(i=1;i<=3;i++){print $i}}' /etc/passwd
root
x
0
//输出第一道第三个字段,输出格式不同
[root@localhost ~]# awk -F: '{for(i=1;i<=3;i++){printf "%s",$i};printf "\n"}' /etc/passwd
rootx0
binx1
//循环中可以根据自己的需求,加上break和continue语句,这里说一下next语句:
//next 提前结束对本行文本的处理
[root@localhost ~]# awk -F: '{if($3%2==1){next};print $1}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
awk的内置函数
1、split()返回一个下标从零开始的一维数组,split函数包含指定数目的子字符串。
2、system(command) 执行系统命令
3、systime() 显示当前时间,返回的是时间戳
4、substr() 截取子字符串
例12
//1、查看当前在线客户端前10名
[root@localhost ~]# netstat -ant | awk '$1~/^tcp$/&&/:22/{split($5,clients,":");IPS[clients[1]]++}END{for(i in IPS){print IPS[i],i}}' | sort -nr | head -n 10
1 192.168.100.1
1 0.0.0.0
//2、返回的是执行状态码,因为我没有/tmp/ls.log文件,所以是标准错误
[root@localhost ~]# awk 'BEGIN{a=system("ls /tmp/ls.log&>/dev/null");print a}'
2
//3、1544626789是linux时间戳,单位是秒数
[root@localhost ~]# awk 'BEGIN{a=system("ls /tmp/ls.log&>/dev/null");print a;print systime()}'
2
1544626789 //linux时间戳,单位是秒数
//4、截取变量A里的第二个和第三个字符
[root@localhost ~]# awk 'BEGIN{A="tom is cat";b=substr(A,2,3);print b}'
om