工作原理
逐行读取文本
,默认以空格或tab键
为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。- sed命令常用于
一整行的处理
,而awk比较倾向于将一行分成多个"字段"然后再进行处理。awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。在使用awk命令的过程中,可以使用逻辑操作符"&&"表示"与"、"||"表示"或"、"!" 表示"非":还可以进行简单的数学运算,如+、-、*、/、%、^分别表示加、减、乘、除、取余和乘方。
AWK 工作流程可分为三个部分:
-
读输入文件之前执行的代码段(由BEGIN关键字标识)。
-
主循环执行输入文件的代码段。
-
读输入文件之后的代码段(由END关键字标识)。
-
1、通过关键字 BEGIN 执行 BEGIN 块的内容,即 BEGIN 后花括号 {} 的内容。
-
2、完成 BEGIN 块的执行,开始执行body块。
-
3、读入有 \n 换行符分割的记录。
-
4、将记录按指定的域分隔符划分域,填充域,0 则表示所有域(即一行内容),0 则表示所有域(即一行内容),0 则表示所有域(即一行内容),1 表示第一个域,$n 表示第 n 个域。
-
5、依次执行各 BODY 块,pattern 部分匹配该行内容成功后,才会执行 awk-commands 的内容。
-
6、循环读取并执行各行直到文件结束,完成body块执行。
-
7、开始 END 块执行,END 块可以输出最终结果。
命令格式
erlang
复制代码
awk 选项 '模式或条件{操作}′ 文件1 文件2 ...
awk -f 脚本文件 文件1 文件2 ...
awk常见的内建变量(可直接用)如下所示:
FS:列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与"-F"作用相同
NF:当前处理的行的字段个数
NR:当前处理的行的行号(序数)
$o:当前处理的行的整行内容
$n:当前处理行的第n个字段(第n列)
FILENAME:被处理的文件名
RS:行分隔符。awk从文件上读取资料时,将根据s的定义把资料切割成许多条记录,而awk一次仅读入一条记录,以进行处理。预设值是'\n'
$0
- 在shell主代码中代表的是脚本名
- 在函数体重代表的是函数名
- 在awk的命令中代表的是当前整行内容
按行输出文本
不同位置的$1的含义
#!/bin/bash
myfunc() {
awk '{peint $1}'$1 #括号里面的$1代表输出当前行的第一个字段
#外面的$1调用函数时后面根的位置变量
}
#### main ###
myfunc $1 #执行脚本时第一个位置变量
显示全部内容
[root@localhost ~]# awk '{print}' 3.txt
one
two
three
four
five
six
seven
eigh
nine
ten
[root@localhost ~]# awk '{print $0}' 3.txt
one
two
three
four
five
six
seven
eigh
nine
ten
双引号也可以输出全文
[root@localhost mm]# awk "{print}" 3.txt
one
two
three
four
five
six
seven
eigh
nine
ten
[root@localhost ~]# awk "{print $0}" 3.txt
//加了双引号以后$就有特殊意义了,AWK将无法识别$符号
0
0
0
0
0
0
0
0
0
0
[root@localhost ~]# awk "{print$0}" 3.txt
//一定要用双引号的话可以使用\号转译即可
one
two
three
four
five
six
seven
eigh
nine
ten
输出一到三行的内容
NR命令可以输出行
[root@localhost ~]# awk 'NR==1,NR==3 {print $0}' 3.txt
one
two
three
输出第四行到第八行的两种方法
[root@localhost ~]# awk 'NR==4,NR==8{print $0}' 3.txt
four
five
six
seven
eigh
[root@localhost ~]# awk '(NR>=4)&&(NR<=8) {print $0}' 3.txt
four
five
six
seven
eigh
输出四和八行
scss
复制代码
[root@localhost ~]# awk '(NR==4)||(NR==8) {print $0}' 3.txt
four
eigh
输出奇数行与偶数行
[root@localhost ~]# awk '(NR%2)==1 {print $0}' 3.txt
one
three
five
seven
nine
[root@localhost ~]# awk '(NR%2)==0 {print $0}' 3.txt
two
four
six
eigh
ten
awk可以使用//来找行里面的内容(也可以配合正则表达式)
[root@localhost ~]# awk '/root/ {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# awk '/^root/ {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# awk '/bash$/ {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
w:x:1000:1000:w:/home/w:/bin/bash
wangwu:x:1001:1001::/home/wangwu:/bin/bash
awk 'BEGIN{操作1}; [条件]{操作2}; END{操作3}' 文件x
模式
BEGIN{操作1} awk在读取文件之前执行的操作
[条件]{操作2} awki逐行读取文件时执行的操作
END {操作3 } awk在处理完文件所有行之后执行的操作
awk 'BEGIN {x=0} ;//bin/bash$/{x++};END {print x} ' /etc/passwd
awk 'BEGIN {x=0} //AWK在执行命令之前会给/etc/passwd赋一个值给X
//bin/bash$/{x++} //AWK根据条件去寻找行,会转译bin bash的两个斜杠所在的行 每个包含bin bash的话加1
END {print x} //输出x的值
统计以nologin结尾的行
[root@localhost ~]# grep -c "nologin$" /etc/passwd
39
[root@localhost ~]# awk 'BEGIN {a=0}; /nologin$/ {a++}; END {print a}' /etc/passwd
39
[root@localhost ~]# awk 'BEGIN {a=0}; /nologin$/ {print a;a++}; END {print "共有"a"行"}' /etc/passwd
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
共有39行
按字段输出文本
列出状态列
[root@localhost ~]# ps -elf | awk '{print $2}'
S
S
S
S
S
S
过滤空闲的内存空间
[root@localhost ~]# free | awk '{print $3}'
free
783220
0
[root@localhost ~]# free |grep Mem: |awk '{print $3}'
783468
[root@localhost ~]# free |awk 'NR==2 {print $3}'
783356
[root@localhost ~]# free | awk '/Mem:/ {print $3}' //字符串也可以查找
782968
找到本机的IP地址与MAC地址
[root@localhost ~]# ifconfig | awk 'NR==2 {print $2,$4}'
192.168.85.10 255.255.255.0
[root@localhost ~]# ifconfig ens33 | awk '/RX p/ {print $5}' //入站流量
1410280
[root@localhost ~]# ifconfig ens33 | awk '/TX p/ {print $5}' //出站流量
813112
加单位输出
[root@localhost ~]# ifconfig ens33 | awk '/TX p/ {print $5,$4}'
821272 bytes
-F 指定分隔符
[root@localhost ~]# awk '{print $1,$3}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
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
[root@localhost ~]# awk -F ':' '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
查看UDI号大于500的
[root@localhost ~]# awk -F ':' '$3>=500 {print $1,$3}' /etc/passwd
polkitd 999
libstoragemgmt 998
colord 997
saslauth 996
setroubleshoot 995
chrony 994
geoclue 993
sssd 992
nfsnobody 65534
gnome-initial-setup 991
[root@localhost ~]# awk -F ':' '!($3<=500) {print $1,$3}' /etc/passwd
//!号取反也可以实现
polkitd 999
libstoragemgmt 998
colord 997
saslauth 996
setroubleshoot 995
chrony 994
geoclue 993
sssd 992
nfsnobody 65534
gnome-initial-setup 991
w 1000
wangwu 1001
AWK模式
[root@localhost ~]# awk 'BEGIN{FS=":"}; {print $1,$3}' /etc/passwd
//使用BEGIN这个模式后,系统在处理文件之前,会先把FS的值改变,再去处理print的操作
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
在使用if语句的时候需要主意两边都要加上{}
[root@localhost ~]# awk -F ':' '{if($3<=10) {print $1,$3}}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
UID≥JID 输出UID号 UID<JID 输出JID号
[root@localhost ~]# awk -F ':' '{max=($3>=$4)?$3:$4; {print $1,max}}' /etc/passwd
root 0
bin 1
daemon 2
adm 4
lp 7
sync 5
shutdown 6
halt 7
mail 12
输出行号与内容
[root@localhost ~]# sed -n '=;p' 3.txt
1
one
2
two
3
three
4
four
5
five
6
six
7
seven
8
eigh
9
nine
10
ten
[root@localhost ~]# awk '{print NR,$0}' 3.txt
1 one
2 two
3 three
4 four
5 five
6 six
7 seven
8 eigh
9 nine
10 ten
包含o的行 ~包含的意思
[root@localhost ~]# awk '$1~"o"{print NR,$0}' 3.txt
1 one
2 two
4 four
通过管道,双引号调用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,$0} ;END{print NR}'
1 /usr/local/sbin
2 /usr/local/bin
3 /usr/sbin
4 /usr/bin
5 /root/bin
查找已有的用户个数
[root@localhost ~]# grep -c "bash$" /etc/passwd
34
[root@localhost ~]# awk '/bash$/ {print $0}' /etc/passwd |wc -l
34
[root@localhost ~]# awk '/bash$/ {print $0 | "wc -l"}' /etc/passwd
34
算出当前内存的空闲率
[root@localhost ~]# free |awk '/Mem:/ {print $3/$2*100}' | awk -F. '{print $1"%"}'
8%
[root@localhost ~]# free |awk '/Mem:/ {print int($3/$2*100)"%"}'
8%
[root@localhost ~]# top -b -n1 | awk '/Cpu/{print $8}'
但值不为100时就会出现问题
96.9
[root@localhost ~]# top -b -n1 | awk '/Cpu/{print $8}'
id,
[root@localhost ~]# top -b -n1 | awk -F , '/Cpu/{print $4}'
100.0 id
[root@localhost ~]# top -b -n1 | awk -F , '/Cpu/{print $4}' | awk '{print $1}'
96.9
[root@localhost ~]# top -b -n1 | awk -F , '/Cpu/{print $4}' | awk '{print $1}'
100.0
[root@localhost ~]# top -b -n1 | awk -F , '/Cpu/{print $4}' | awk '{print $1"%"}'
100.0%
想查看服务器是否有重启过(查看上一次开机时间)
[root@localhost ~]# cat /proc/uptime
179.17 //系统的启动时间单位(秒) 331.86 //系统的空闲时间但是(秒)
[root@localhost ~]# date -d "179.17 second ago" +"%Y%m%d %H:%M:%S"
20220912 10:23:53
[root@localhost ~]# date -d "$(awk '{print $1}' /proc/uptime) second ago" +"%Y%m%d %H:%M:%S"
20220912 10:18:43
奇数,偶数
[root@localhost ~]# seq 10 | awk '{getline; print $0}'
2
4
6
8
10
[root@localhost ~]# seq 10 | awk '{print $0; getline }'
1
3
5
7
9
- 当getline左右无重定向符"<"或"|"时,awk首先读取到了第一行,就是1,然后getline,就得到了1下面的第二行,就是2,因为yetline之后,awk会改变对应的NF,NR,FNR和o等内部变量,所以此时的o等内部变量,所以此时的o等内部变量,所以此时的o的值就不再是1,而是2了,然后将它打印出来。
- 当getline左右有重定向符"<"或"|"时,getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该立件的第—行.而不是隔行。
系统名称
[root@localhost ~]# awk 'BEGIN {"hostname" | getline; {print $0}}'
localhost.localdomain
[root@localhost ~]# w | awk 'NR>=3 {print $0 | "wc -l"}'
1
[root@localhost ~]# awk 'BEGIN{n=0; while("w" | getline) n++; print n-2}'
1
总结
awk 'BEGIN{操作1}; [条件]{操作2}; END{操作3}' 文件x
模式
BEGIN{操作1} awk在读取文件之前执行的操作
[条件]{操作2} awki逐行读取文件时执行的操作
END {操作3 } awk在处理完文件所有行之后执行的操作
cpu负载 uptime w top
cpu使用率 top vmstat
内存 free top vmstat
硬盘空间 df
网卡流量 ifconfig
安装的软件包数量 rpm -qa l wc -l
账户数量 cat letc/passwd l wc -l
登录账户 who wusers
进程数量 ps aux l wc -l
ssh登录 /var/ log/ secure