Linux Shell编程 数据筛选与处理 AWK 现场笔记
一、数据处理方法
- 数据采集
- 数据清洗
- 数据分析
- 数据展示
二、Shell脚本数据处理的方法
- 数据检索 grep egrep
- 数据整理 cut tr
- 数据处理 uniq sort tee paste xargs
- 数据展示 echo cat
之前的脚本中我们都是通过grep、cut、tr、uniq、sort等命令通过管道组合在一起将字符串检索出来,然后在通过shell中对应的运算得到结果,在数据检索过程中大家可能也体会到了其中的辛苦和蹩脚。没办法,会的就这么多,还需要完成任务。
缺点:
复杂的命令组合
多次运算
学习曲线高
三、awk介绍
在日常计算机管理中,总会有很多数据输出到屏幕或者文件,这些输出包含了标准输出、标准错误输出。默认情况下,这些信息全部输出到默认输出设备—屏幕。然而,大量的数据输出中,只有一小部分是我们需要重点关注的,我们需要把我们需要的或者关注的这些信息过滤或者提取以备后续需要时调用。早先的学习中,我们学过使用grep来过滤这些数据,使用cut、tr命令提出某些字段,但是他们都不具备提取并处理数据的能力,都必须先过滤,再提取转存到变量,然后在通过变量提取去处理,比如:
内存使用率的统计步骤
1) 通过free -m提取出内存总量,赋值给变量 memory_totle
2)通过free -m提取出n内存使用量,赋值给变量memory_use
3)通过数学运算计算内存使用率
需要执行多步才能得到内存使用率,那么有没有一个命令能够集过滤、提取、运算为一体呢?当然,就是今天我要给大家介绍的命令:awk(三位作者姓分别为:Aho、Weingberger 和 Kernighan)
awk是一种可以处理数据、产生格式化报表的语言,功能十分强大。
我们使用awk主要作用为:数据提取、数据处理、生成格式化报表
- awk 认为文件中的每一行是一条记录
- 记录与记录的分隔符为换行符
- 每一列是一个字段
- 字段与字段的分隔符默认是一个或多个空格或tab制表符
平行命令还有gawk、pgawk、dgawk等。
四、awk工作原理
读取数据,将每一行数据视为一条记录(record)每条记录以字段分隔符分成若干字段,然后输出各个字段的值
五、awk应用场景
- 字符串截取
- 数据运算
- 生成格式化报表
六、awk语法
awk [options] [BEGIN] {program} [END] [FILENAME]
awk 程序脚本由左大括号和右大括号定义。脚本命令必须放置在两个大括号之间。由于awk命令行假定脚本是单文本字符串,所以必须将脚本包括在单引号内。
常用命令选项
-F fs 指定描绘一行中数据字段的文件分隔符 默认为空格
-f file 指定读取程序的文件名
-v var=value 定义awk程序中使用的变量和默认值
awk程序运行优先级是:
1)BEGIN: 在开始处理数据流之前执行,可选项
2)program: 如何处理数据流,必选项
3)END: 处理完数据流后执行,可选项
七、awk基本应用
7.1 演示用例文本
[root@localhost ~]# cat awkfile
1 the quick brown fox jumps over the lazy dog.
2 the quick brown fox jumps over the lazy dog.
3 the quick brown fox jumps over the lazy dog.
4 the quick brown fox jumps over the lazy dog.
5 the quick brown fox jumps over the lazy dog.
7.2 awk对字段(列)的提取
字段提取:提取一个文本中的一列数据并打印输出
字段相关内置变量:
$0 表示整行文本
$1 表示文本行中的第一个数据字段
$2 表示文本行中的第二个数据字段
$N 表示文本行中的第N个数据字段
$NF 表示文本行中的最后一个数据字段
读入awkfile每行数据并把每行数据打印出来
[root@localhost ~]# awk '{print $0}' awkfile
1 the quick brown fox jumps over the lazy dog.
2 the quick brown fox jumps over the lazy dog.
3 the quick brown fox jumps over the lazy dog.
4 the quick brown fox jumps over the lazy dog.
5 the quick brown fox jumps over the lazy dog.
读入awkfile打印第六列内容
[root@localhost ~]# awk '{print $6}' awkfile
jumps
jumps
jumps
jumps
jumps
读入awkfile打印最后一列内容
[root@localhost ~]# awk '{print $NF}' awkfile
dog.
dog.
dog.
dog.
dog.
7.3 awk对字段(列)的提取案例
使用grep、tr、cut对内存信息进行提取
[root@localhost ~]# free -m | grep "Mem:" | tr -s " " | cut -d " " -f 2
1980
[root@localhost ~]# free -m | grep "Mem:" | tr -s " " | cut -d " " -f 3
404
使用awk对内存信息进行提取
[root@localhost ~]# free -m | grep "Mem:" | awk '{print $2}'
1980
[root@localhost ~]# free -m | grep "Mem:" | awk '{print $3}'
404
对/etc/passwd文件中的列进行提取
文件内容默认行分隔符为一个或多个空格或tab。如果不是,截取时,需要使用-F指定分隔符。
[root@smartgo ~]# awk -F ":" '{print $1}' /etc/passwd
7.4 awk对记录(行)的提取
记录提取:提取一个文本中的一行并打印输出
记录的提取方法有两种:a、通过行号 b、通过正则匹配
记录相关内置变量
NR: 指定行号
提取awkfile第三行数据
指定行号为3,$0是指指定行号行内的所有内容。
[root@localhost ~]# awk 'NR==3{print $0}' awkfile
3 the quick brown fox jumps over the lazy dog.
指定行的第一个字段精确匹配字符串为3
[root@localhost ~]# awk '$1=="3"{print $0}' awkfile
3 the quick brown fox jumps over the lazy dog.
7.5 awk对记录(行)的提取案例
[root@smartgo ~]# awk 'NR==2{print $0}' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
[root@smartgo ~]# free -m
total used free shared buff/cache available
Mem: 1980 744 472 17 763 999
Swap: 2047 0 2047
[root@smartgo ~]# free -m | awk 'NR==2{print $0}'
Mem: 1980 744 472 17 763 999
直接截取
[root@smartgo ~]# free -m | awk 'NR==2{print $2}'
1980
[root@smartgo ~]# free -m | awk 'NR==2{print $3}'
744
NR相当于X轴
$2或$3相当于Y轴
先行截取再列截取
[root@smartgo ~]# free -m | awk 'NR==2{print $0}' | awk '{print $2}'
1980
[root@smartgo ~]# free -m | awk 'NR==2{print $0}' | awk '{print $3}'
745
通过正则表达式匹配
[root@192 shell07]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.2.128 www.aiops.com.cn
[root@192 shell07]# awk '/localhost/{print $0}' /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@192 shell07]# awk '/www/{print $0}' /etc/hosts
192.168.2.128 www.aiops.com.cn
[root@192 shell07]# awk '/l.*/{print $0}' /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@192 shell07]# awk '/^127/{print $0}' /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
或
[root@192 shell07]# free -m | awk 'NR==2{print $0}'
Mem: 972 386 216 16 369 417
[root@192 shell07]# free -m | awk '/^Mem:/{print $0}'
Mem: 972 386 216 16 369 417
7.6 awk命令选项
7.6.1 -F
说明: 指定字段与字段的分隔符
当输出的数据流字段格式不是awk默认的字段格式时,我们可以使用-F命令选项来重新定义数据流字段分隔符。
awk输出字段默认的分隔符也是空格
处理的文件是/etc/passwd,打印第一列、第三列、最后一列
[root@smartgo ~]# awk -F ':' '{print $1,$3,$NF}' /etc/passwd
root 0 /bin/bash
bin 1 /sbin/nologin
daemon 2 /sbin/nologin
adm 3 /sbin/nologin
lp 4 /sbin/nologin
sync 5 /bin/sync
shutdown 6 /sbin/shutdown
halt 7 /sbin/halt
mail 8 /sbin/nologin
operator 11 /sbin/nologin
games 12 /sbin/nologin
ftp 14 /sbin/nologin
nobody 99 /sbin/nologin
systemd-network 192 /sbin/nologin
dbus 81 /sbin/nologin
polkitd 999 /sbin/nologin
libstoragemgmt 998 /sbin/nologin
colord 997 /sbin/nologin
rpc 32 /sbin/nologin
saned 996 /sbin/nologin
gluster 995 /sbin/nologin
amandabackup 33 /bin/bash
saslauth 994 /sbin/nologin
abrt 173 /sbin/nologin
rtkit 172 /sbin/nologin
pulse 171 /sbin/nologin
radvd 75 /sbin/nologin
unbound 993 /sbin/nologin
chrony 992 /sbin/nologin
rpcuser 29 /sbin/nologin
nfsnobody 65534 /sbin/nologin
qemu 107 /sbin/nologin
tss 59 /sbin/nologin
usbmuxd 113 /sbin/nologin
geoclue 991 /sbin/nologin
ntp 38 /sbin/nologin
sssd 990 /sbin/nologin
setroubleshoot 989 /sbin/nologin
gdm 42 /sbin/nologin
gnome-initial-setup 988 /sbin/nologin
sshd 74 /sbin/nologin
avahi 70 /sbin/nologin
postfix 89 /sbin/nologin
tcpdump 72 /sbin/nologin
tom 1000 /bin/bash
7.6.2 -f file
说明:如果awk命令是日常重复工作,而又没有太多变化,可以将程序写入文件,每次使用-f调用程序文件就好,方便,高效。
[root@localhost ~]# cat abc
{print $1,$3,$NF}
[root@localhost ~]# awk -f abc awkfile
1 quick dog.
2 quick dog.
3 quick dog.
4 quick dog.
5 quick dog.
[root@localhost shellawk]# awk -F ":" -f abc /etc/passwd
7.6.3 -v
说明:定义变量,既然作者写awk的时候就是按着语言去写的,那么语言中最重要的要素—变量肯定不能缺席,所以可以使用-v命令选项定义变量
定义了一个变量 name=xiaoming,然后调用变量读出数据。
[root@localhost ~]# awk -v name='xiaoming' 'BEGIN{print name}'
xiaoming
7.7 awk程序执行优先级
关于awk程序的执行优先级,BEGIN是优先级最高的代码块,是在执行PROGRAM之前执行的,不需要提供数据源,因为不涉及到任何数据的处理,也不依赖与PROGRAM代码块;PROGRAM是对数据流干什么,是必选代码块,也是默认代码块。所以在执行时必须提供数据源;END是处理完数据流后的操作,如果需要执行END代码块,就必须需要PROGRAM的支持,单个无法执行。
动作 | 说明 | 数据源 |
---|---|---|
BEGIN | 处理数据源之前干什么 | 不需要数据源就可以执行 |
PROGRAM | 对数据源干什么 【默认必须有】 | 需要数据源 |
END | 处理完数据源后干什么 | 需要program 需要数据源 |
BEGIN不需要数据源
[root@localhost ~]# awk 'BEGIN{print "hello smartgo"}'
hello smartgo
默认progam必须有数据源
[root@localhost ~]# awk '{print "hello smartgo"}'
^C
[root@localhost ~]# awk '{print "hello smartgo"}' awkfile
hello smartgo
hello smartgo
hello smartgo
hello smartgo
hello smartgo
END必须有数据源
[root@localhost ~]# awk 'END{print "hello smartgo"}'
^C
[root@localhost ~]# awk 'END{print "hello smartgo"}' awkfile
hello smartgo
案例
[root@localhost ~]# awk 'END{print "end======="}BEGIN{print "start========="}{print $0}' awkfile
start=========
1 the quick brown fox jumps over the lazy dog.
2 the quick brown fox jumps over the lazy dog.
3 the quick brown fox jumps over the lazy dog.
4 the quick brown fox jumps over the lazy dog.
5 the quick brown fox jumps over the lazy dog.
end=======
案例
[root@localhost ~]# cat num
1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# awk '{sum+=$1}END{print sum}' num
55
[root@localhost ~]# awk '{sum+=$1;print sum}' num
1
3
6
10
15
21
28
36
45
55
八、awk高级应用
awk是一门编程语言,那么就会符合语言的特性,除了可以定义变量外,还可以定义数组,还可以进行运算,流程控制等等。
8.1 awk定义变量
[root@localhost ~]# awk -v name='xiaoming' 'BEGIN{print name}'
xiaoming
[root@localhost ~]# awk 'BEGIN{name="xiaoming";print name}'
xiaoming
变量值必须使用双引号,不能使用单引号。
awk引用shell中的变量方法
[root@webserver1 shell07]# name1=tom
[root@webserver1 shell07]# awk 'BEGIN{print '$name1'}'
[root@webserver1 shell07]# awk 'BEGIN{print "'$name1'"}'
tom
计算内存使用率
[root@localhost ~]# cat /proc/meminfo
MemTotal: 2028088 kB
MemFree: 1187240 kB
MemAvailable: 1394700 kB
Buffers: 2244 kB
Cached: 317504 kB
SwapCached: 0 kB
Active: 303276 kB
Inactive: 266140 kB
Active(anon): 250644 kB
Inactive(anon): 11708 kB
Active(file): 52632 kB
Inactive(file): 254432 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 2097148 kB
SwapFree: 2097148 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 249684 kB
Mapped: 101644 kB
Shmem: 12688 kB
Slab: 109384 kB
SReclaimable: 64260 kB
SUnreclaim: 45124 kB
KernelStack: 7232 kB
PageTables: 20436 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 3111192 kB
Committed_AS: 2129704 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 180392 kB
VmallocChunk: 34359310332 kB
HardwareCorrupted: 0 kB
AnonHugePages: 65536 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 96128 kB
DirectMap2M: 2000896 kB
DirectMap1G: 0 kB
取出总量
[root@webserver1 shell07]# awk 'NR==1{t=$2;print $2}' /proc/meminfo
995684
取出空闲量
[root@webserver1 shell07]# awk 'NR==2{f=$2;print $2}' /proc/meminfo
165988
[root@webserver1 shell07]# awk 'NR==2{f=$2;print "空闲量:"$2}' /proc/meminfo
空闲量:165988
取出缓存总量
[root@webserver1 shell07]# awk 'NR==4{b=$2}NR==5{c=$2;print "缓存总量:"b+c}' /proc/meminfo
缓存总量:318276
取空闲量+缓存问题
[root@webserver1 shell07]# awk 'NR==2{f=$2}NR==4{b=$2}NR==5{c=$2;print "空闲总量:"f+b+c}' /proc/meminfo
计算出内存使用的百分比:
[root@webserver1 shell07]# awk 'NR==1{t=$2}NR==2{f=$2}NR==4{b=$2}NR==5{c=$2;print "内存使用率:"(t-f-b-c)*100/t"%" }' /proc/meminfo
内存使用率:51.3765%
验证:
[root@webserver1 shell07]# free -m | awk 'NR==2{print $3*100/$2"%"}'
44.4444%
下面值是错误的,少减了缓存。
[root@localhost ~]# awk 'NR==1{t=$2}NR==2{f=$2;print (t-f)*100/t}' /proc/meminfo
41.5617
NR==1是第一行
NR==2是第二行
t是第一行第二列内容 内存总量
f是第二行第二列内容 内存空闲总量
t-f为内存使用量
内存使用量除以内存总量就是内存使用量的百分比。
8.2 awk定义数组
数组定义方式:
数组名[索引]=值
定义一个a数组,包含两个元素,下标分别为:0和1.
[root@localhost ~]# awk 'BEGIN{a[0]=100;a[1]=200;print a[0]}'
100
[root@localhost ~]# awk 'BEGIN{a[0]=100;a[1]=200;print a[1]}'
200
[root@localhost ~]# awk 'BEGIN{a[0]=100;a[1]=200;print a[0],a[1]}'
100 200
自定义数组下标,类似于shell关联数组。
[root@localhost ~]# awk 'BEGIN{a[name1]="tom";print a[name1]}'
tom
[root@localhost ~]# awk 'BEGIN{a[name2]="jack";print a[name2]}'
jack
[root@localhost ~]# awk 'BEGIN {
a["name1"]="tom";
a["name2"]="jack"
print a["name1"] "\n" a["name2"]
}'
tom
jack
8.3 awk运算
- 赋值运算 =
- 比较运算 > >= == < <= !=
- 算术运算 + - * / % ** ++ –
- 逻辑运算 && ||
- 匹配运算 ~ !~ 精确匹配 == !=
8.3.1 赋值运算
说明:主要是对变量或者数组赋值
[root@localhost ~]# awk -v name='xiaoming' 'BEGIN{print name}'
xiaoming
[root@localhost ~]# awk 'BEGIN{school="abc";print school}'
abc
[root@localhost ~]# awk 'BEGIN{array[0]=100;print array[0]}'
100
8.3.2 比较运算
说明:数值可直接比较;字符串则按ascii编码顺序表比较。如果结果返回为真则用1表示,如果返回为假则用0表示
数值比较
数据源
[root@localhost ~]# cat num
1
2
3
4
5
6
7
8
9
10
$1大于5的输出
[root@localhost ~]# awk '$1>5{print $0}' num
6
7
8
9
10
$1大于或等于5的输出
[root@localhost ~]# awk '$1>=5{print $0}' num
5
6
7
8
9
10
$1等于5的输出
[root@localhost ~]# awk '$1==5{print $0}' num
5
$1小于5的输出
[root@localhost ~]# awk '$1<5{print $0}' num
1
2
3
4
$1小于或等于5的输出
[root@localhost ~]# awk '$1<=5{print $0}' num
1
2
3
4
5
$1不等于5的输出
[root@localhost ~]# awk '$1!=5{print $0}' num
1
2
3
4
6
7
8
9
10
[root@localhost ~]# awk '$1>4{print $0}' awkfile
5 the quick brown fox jumps over the lazy dog.
[root@localhost ~]# awk 'BEGIN{print 100 >= 1 }'
1
[root@localhost ~]# awk 'BEGIN{print 100 == 1 }'
0
[root@localhost ~]# awk 'BEGIN{print 100 <= 1 }'
0
[root@localhost ~]# awk 'BEGIN{print 100 < 1 }'
0
[root@localhost ~]# awk 'BEGIN{print 100 != 1 }'
1
有问题的地方,需要注意:
[root@localhost ~]# awk 'BEGIN{print 4<3 }'
0
下面这个有问题
[root@localhost ~]# awk 'BEGIN{print 4>3 }'
[root@localhost ~]# ls
3
字符比较
[root@localhost ~]# awk 'BEGIN{print "a" >= "b" }'
0
[root@localhost ~]# awk 'BEGIN{print "a" <= "b" }'
1
8.3.3 算术运算
[root@localhost ~]# awk 'BEGIN{print 100+3}'
103
[root@localhost ~]# awk 'BEGIN{print 100-3}'
97
[root@localhost ~]# awk 'BEGIN{print 100*3}'
300
[root@localhost ~]# awk 'BEGIN{print 100/3}'
33.3333
[root@localhost ~]# awk 'BEGIN{print 100%3}'
1
[root@localhost ~]# awk 'BEGIN{print 100**3}'
1000000
[root@localhost ~]# awk 'BEGIN{print 5.5-2.3}'
3.2
[root@localhost ~]# awk -v 'count=0' 'BEGIN{count++;print count}'
1
[root@localhost ~]# awk -v 'count=0' 'BEGIN{count--;print count}'
-1
[root@webserver1 shell07]# num1=1
[root@webserver1 shell07]# num2=2
[root@webserver1 shell07]# awk 'BEGIN{print "'$num1'"+"'$num2'"}'
3
[root@webserver1 shell07]# cat awk1.sh
#!/bin/bash
# Desc:awk
read -p "plz num1:" num1
read -p "plz char:" char
read -p "plz num2:" num2
awk 'BEGIN{print "'$num1'" '$char' "'$num2'"}'
8.3.4 逻辑运算
与运算:真真为真,真假为假,假假为假
[root@localhost ~]# awk 'BEGIN{print 100>=2 && 100>=3 }'
1
[root@localhost ~]# awk 'BEGIN{print 100>=2 && 1>=100 }'
0
或运算:真真为真,真假为真,假假为假
[root@localhost ~]# awk 'BEGIN{print 100>=2 || 1>=100 }'
1
[root@localhost ~]# awk 'BEGIN{print 100>=200 || 1>=100 }'
0
8.3.5 匹配运算
精确匹配
[root@localhost ~]# awk -F ":" '$1=="root"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
精确不匹配
[root@localhost ~]# awk -F ":" '$1!="root"{print $0}' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
libstoragemgmt:x:998:995:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
colord:x:997:994:User for colord:/var/lib/colord:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
saned:x:996:993:SANE scanner daemon user:/usr/share/sane:/sbin/nologin
gluster:x:995:992:GlusterFS daemons:/run/gluster:/sbin/nologin
amandabackup:x:33:6:Amanda user:/var/lib/amanda:/bin/bash
saslauth:x:994:76:Saslauthd user:/run/saslauthd:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
unbound:x:993:988:Unbound DNS resolver:/etc/unbound:/sbin/nologin
chrony:x:992:987::/var/lib/chrony:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
qemu:x:107:107:qemu user:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
geoclue:x:991:985:User for geoclue:/var/lib/geoclue:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
sssd:x:990:984:User for sssd:/:/sbin/nologin
setroubleshoot:x:989:983::/var/lib/setroubleshoot:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
gnome-initial-setup:x:988:982::/run/gnome-initial-setup/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
tom:x:1000:1000:tom:/home/tom:/bin/bash
harry:x:1001:1001::/home/harry:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
tom1:x:1002:1002::/home/tom1:/bin/bash
jarry1:x:1003:1003::/home/jarry1:/bin/bash
harry1:x:1004:1004::/home/harry1:/bin/bash
zs1:x:1005:1005::/home/zs1:/bin/bash
zs:x:1006:1006::/home/zs:/bin/bash
lisi:x:1007:1007::/home/lisi:/bin/bash
wangwu:x:1008:1008::/home/wangwu:/bin/bash
模糊匹配
[root@localhost ~]# awk -F ":" '$1~"root"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# awk -F ":" '$1~"ro"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
chrony:x:992:987::/var/lib/chrony:/sbin/nologin
setroubleshoot:x:989:983::/var/lib/setroubleshoot:/sbin/nologin
模糊不匹配
[root@localhost ~]# awk -F ":" '$1!~"ro"{print $0}' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
libstoragemgmt:x:998:995:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
colord:x:997:994:User for colord:/var/lib/colord:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
saned:x:996:993:SANE scanner daemon user:/usr/share/sane:/sbin/nologin
gluster:x:995:992:GlusterFS daemons:/run/gluster:/sbin/nologin
amandabackup:x:33:6:Amanda user:/var/lib/amanda:/bin/bash
saslauth:x:994:76:Saslauthd user:/run/saslauthd:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
unbound:x:993:988:Unbound DNS resolver:/etc/unbound:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
qemu:x:107:107:qemu user:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
geoclue:x:991:985:User for geoclue:/var/lib/geoclue:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
sssd:x:990:984:User for sssd:/:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
gnome-initial-setup:x:988:982::/run/gnome-initial-setup/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
tom:x:1000:1000:tom:/home/tom:/bin/bash
harry:x:1001:1001::/home/harry:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
tom1:x:1002:1002::/home/tom1:/bin/bash
jarry1:x:1003:1003::/home/jarry1:/bin/bash
harry1:x:1004:1004::/home/harry1:/bin/bash
zs1:x:1005:1005::/home/zs1:/bin/bash
zs:x:1006:1006::/home/zs:/bin/bash
lisi:x:1007:1007::/home/lisi:/bin/bash
wangwu:x:1008:1008::/home/wangwu:/bin/bash
8.4 awk环境变量
变量 | 描述 |
---|---|
FIELDWIDTHS | 以空格分隔的数字列表,用空格定义每个数据字段的精确宽度 |
FS | 输入字段分隔符号 数据源的字段分隔符 -F |
OFS | 输出字段分隔符号 |
RS | 输入记录分隔符 |
ORS | 输出记录分隔符号 |
FIELDWIDTHS:重定义列宽并打印,注意不可以使用$0打印所有,因为$0是打印本行全内容,不会打印你定义的字段
[root@localhost ~]# awk 'BEGIN{FIELDWIDTHS="5 2 8"}NR==1{print $1,$2,$3}' /etc/passwd
root: x: 0:0:root
补充:printf 格式化输出
# awk -F ":" '{printf "USERNAME:%-15s UID:%-10s \n",$1,$3}' passwd
# awk -F ":" 'BEGIN{printf "%30s \n","USERLIST"}{printf "USERNAME:%-15s PASS:%-10s UID:%-10s \n",$1,$2,$3}END{printf "%40s \n","OVER"}' passwd
FS:指定数据源中字段分隔符,类似命令选项-F
[root@localhost ~]# awk 'BEGIN{FS=":"}NR==1{print $1,$3,$NF}' /etc/passwd
root 0 /bin/bash
或
#awk 'BEGIN{FS=":"}$1=="root"{print $1,$3}' passwd
或
#awk -F ":" 'NR==1{print $0}' passwd
#awk -F ":" '$1=="root"{print $0}' passwd
OFS:指定输出到屏幕后字段的分隔符
[root@localhost ~]# awk -F ":" 'NR==1{print "ACCOUNT:" $1,"UID:" $3,"SHELL:" $NF}' /etc/passwd
ACCOUNT:root UID:0 SHELL:/bin/bash
不想使用上述方式隔离,可以使用下面的方式隔离,使用OFS定义即可。
[root@localhost ~]# awk 'BEGIN{FS=":";OFS="-"}NR==1{print $1,$3,$NF}' /etc/passwd
root-0-/bin/bash
或
awk -F ":" 'BEGIN{OFS="-"}NR==1{print $1,$2}' passwd
root-x
RS:指定记录的分隔符,可以用于把回车做为分隔符取消,让所有行变为一行,然后打印某一列即可。
[root@localhost ~]# cat num
1
2
3
4
5
6
7
8
9
10
取消默认回车做为行分隔符
[root@localhost ~]# awk 'BEGIN{RS=""}{print $1}' num
1
验证
[root@localhost ~]# awk 'BEGIN{RS=""}{print $1,$2,$3,$4,$5,$6,$6,$7,$8,$9,$10}' num
1 2 3 4 5 6 6 7 8 9 10
ORS:输出到屏幕后记录的分隔符,默认为回车
[root@localhost ~]# cat num
1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# awk 'BEGIN{ORS=" "}{print $1}' num
1 2 3 4 5 6 7 8 9 10
RS小案例:
变量 RS 和 ORS 定义了 awk 程序如何处理数据流中的字段,默认情况下,awk 将 RS 和 ORS 设为换行符。默认的 RS 值表明,输入数据流中的每行新文本就是一条新纪录。 有时,你会在数据流中碰到占据多行的字段。典型的例子是包含地址和电话号码的数据,其中地址和电话号码各占一行,例如:
[root@localhost ~]# cat awkaddr.file
tom king
beijing chaoyang
dawanglu 66
13810011002
jack wang
shanghai hongqiao
76nong 1
19811621098
harry li
guangzhou yuexiu
nanjinglu 33
13911821763
[root@localhost ~]# awk 'BEGIN{RS=""}{print $1,$2,$7}' awkaddr.file
tom king 13810011002
jack wang 19811621098
harry li 13911821763
思考:为什么下面的写法也可以?
如果你用默认的 FS 和 RS 变量值来读取这组数据,awk 就会把每行作为一条单独的记录来读取,并将记录中的空格当作字段分隔符,这并不是用户想要的。
要解决这个问题,只需把 FS 变量设置成换行符,这就表明数据流中的每行都是一个单独的字段,每行上的所有数据都属于同一个字段;与此同时,把 RS 变量设置成空字符串,然后在数据记录间留一个空白行,awk 会把每个空白行当作一个记录分隔符。
[root@localhost ~]# awk 'BEGIN{RS="";FS="\n"}{print $1,$4}' awkaddr.file
tom king 13810011002
jack wang 19811621098
harry li 13911821763
8.5 awk流程控制
- if判断语句
- for循环语句
- while循环语句
- do…while语句
- 循环控制
8.5.1 if判断语句
[root@localhost ~]# cat num
1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# awk '$1>5{print $0}' num
6
7
8
9
10
[root@localhost ~]# awk '{if ($1>5) print $0}' num
6
7
8
9
10
[root@localhost ~]# awk '{
> if ($1>5)
> print $0
> }' num
6
7
8
9
10
if else:小于5*2,大于5/2
[root@localhost ~]# awk '{
> if ($1>5)
> print $1/2
> else
> print $1*2
> }' num
2
4
6
8
10
3
3.5
4
4.5
5
或
[root@localhost ~]# awk '{if ($1>5) print $1/2;else print $1*2}' num
2
4
6
8
10
3
3.5
4
4.5
5
8.5.2 for循环语句
[root@localhost ~]# cat awkfor.file
60 50 100
150 30 10
70 100 40
把以上文件每行加起来即可:$1+$2+$3
[root@localhost ~]# awk '{sum=0;for (i=1;i<4;i++){sum+=$i}print sum}' awkfor.file
210
190
210
或
[root@localhost ~]# awk '{
> sum=0
> for (i=1;i<4;i++) {
> sum=sum+$i
> }
> print sum
> }' awkfor.file
210
190
210
8.5.3 while循环语句
说明:先判断再执行
[root@localhost ~]# cat awkwhile.file
60 50 100
150 30 10
70 100 40
[root@localhost ~]# awk '{
> sum=0
> i=1
> while (i<4) {
> sum+=$i
> i++
> }
> print sum
> }' awkwhile.file
210
190
210
8.5.4 do…while循环语句
说明:先执行再判断
[root@localhost ~]# cat awkwhile.file
60 50 100
150 30 10
70 100 40
[root@localhost ~]# awk '{
> sum=0
> i=1
> do {
> sum+=$i
> i++
> } while (i<4)
> print sum
> }' awkwhile.file
210
190
210
8.5.5 循环控制语句
break 跳出循环,继续执行后续语句
[root@localhost ~]# cat awkfor.file
60 50 100
150 30 10
70 100 40
[root@localhost ~]# awk '{
> sum=0
> for (i=1;i<4;i++) {
> sum+=$i
> if (i==2) break
> }
> print sum
> }' awkfor.file
110
180
170
九、awk应用案例
写一个自动检测磁盘使用率的脚本,当磁盘使用空间达到90%以上时,需要发送邮件给相关人员
df -h|egrep -v "(tmp|sr0)" |tail -n +2|tr -d "%"|awk '{if ($5>90) print "磁盘:" $1,"使用率:" $5"%"}' | mail -s "磁盘已满" root@localhost
十、awk用于统计网站访问相关参考资料(扩展)
https://blog.csdn.net/Alen_xiaoxin/article/details/88702565