shell文本处理三剑客之——awk

一、awk的概述

1、awk的概念

逐行读取文本,默认以空格或tab键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令

sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个“字段”然后再进行处理。awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示

在使用awk命令的过程中,可以使用逻辑操作符“&&”表示“与”、“| |”表示“或”、“!“表示“非”;还可以进行简单的数学运算,如+、-、*、/、%、^分别表示加、减、乘、除、取余和乘方

2、awk的工作原理

awk是逐行处理的,逐行处理的意思就是说,当awk处理一个文本时,会一行一行进行处理,处理完当前行,再处理下一行,awk默认以"换行符"为标记,识别每一行,也就是说,awk跟我们人类一样,每次遇到"回车换行",就认为是当前行的结束,新的一行的开始,awk会按照用户指定的分割符去分割当前行,如果没有指定分割符,默认使用空格作为分隔符。

 

$0 表示显示整行 ,$NF表示当前行分割后的最后一列($0和$NF均为内置变量)

注意,$NF 和 NF 要表达的意思是不一样的,对于awk来说,$NF表示最后一个字段,NF表示当前行被分隔符切开以后,一共有几个字段

也就是说,假如一行文本被空格分成了7段,那么NF的值就是7,$NF的值就是$7,  而$7表示当前行的第7个字段,也就是最后一列,那么每行的倒数第二列可以写为$(NF-1)

3、基本格式

awk [选项参数] 'script' var=value file(s)
或
awk [选项参数] -f scriptfile var=value file(s)

4、常见的内建变量(可直接用)

FS∶ 列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与"-F"作用相同
NF∶ 当前处理的行的字段个数。
NR∶ 当前处理的行的行号(序数)。
$0∶当前处理的行的整行内容。
$n∶ 当前处理行的第n个字段(第n列)。
FILENAME∶ 被处理的文件名。
RS∶ 行分隔符。awk从文件上读取资料时,将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录,以进行处理。预设值是’\n’

二、awk的应用一:按行输出文本

1、输出全部内容

[root@weq ~]# cat num.txt 
1
2
3
4
5
6
7
8
9
10
[root@weq ~]# awk '{print}' num.txt 
1
2
3
4
5
6
7
8
9
10
[root@weq ~]# awk '{print $0}' num.txt 
1
2
3
4
5
6
7
8
9
10

  

2、输出指定行的内容

[root@weq ~]# cat num.txt 
1
2
3
4
5
6
7
8
9
10
[root@weq ~]# awk 'NR==3,NR==5 {print $0}' num.txt 
3
4
5
[root@weq ~]# awk '(NR>=3)&&(NR<=5) {print}' num.txt 
3
4
5
[root@weq ~]# awk '(NR==3)&&(NR==5) {print}' num.txt 
[root@weq ~]# awk '(NR==3)||(NR==5) {print}' num.txt 
3
5
[root@weq ~]# awk '(NR<=3)||(NR>=8) {print}' num.txt 
1
2
3
8
9
10
[root@weq ~]# awk '(NR==8) {print}' num.txt 
8

  

3、输出奇数和偶数行的内容

[root@weq ~]# cat num.txt 
1
2
3
4
5
6
7
8
9
10
[root@weq ~]# awk '(NR%2)==1 {print}' num.txt 
1
3
5
7
9
[root@weq ~]# awk '(NR%2)==0 {print}' num.txt 
2
4
6
8
10

  

4、输出包含指定字符的行

[root@weq ~]# cat testfile2
c
bd
abbc
cdd
efg
abc
CDD
[root@weq ~]# awk '/^a/{print}' testfile2
abbc
abc
[root@weq ~]# awk '/c$/{print}' testfile2
c
abbc
abc

  

5、awk包含两种特殊的模式:BEGIN 和 END

5.1 两种模式的概念

BEGIN 模式指定了处理文本之前需要执行的操作:

END 模式指定了处理完所有行之后所需要执行的操作:

BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的动作; awk再处理指定的文本,之后再执行END模式中指定的动作,END{}语句块中, 往往会放入打印结果等语句

5.2  BEGIN模式的应用实例一

BEGIN 模式指定了处理文本之前需要执行的操作:

[root@weq ~]# cat testfile6
zhang 28 male
li 24 female
liu 23 male
wang 21 female
[root@weq ~]# awk 'BEGIN {print "name","age", "sex"}' testfile6
name age sex
[root@weq ~]# awk 'BEGIN {print "name","age", "sex"}' 
name age sex

  

5.2  BEGIN模式的应用实例二

如何让:awk先执行BEGIN模式指定的动作,再根据执我们自定义的动作去操作文本 

[root@weq ~]# cat testfile6
zhang 28 male
li 24 female
liu 23 male
wang 21 female
[root@weq ~]# awk 'BEGIN {print "name","age", "sex"} {print $1,$2,$3}' testfile6 
name age sex
zhang 28 male
li 24 female
liu 23 male
wang 21 female

  

5.3 END模式的应用实例

END模式就是在处理完所有的指定的文本之后,需要指定的动作 

[root@weq ~]# cat testfile6
zhang 28 male
li 24 female
liu 23 male
wang 21 female
[root@weq ~]# awk 'BEGIN {print "name","age", "sex"} {print $1,$2,$3} END{print "lu","18","male"}' testfile6 
name age sex
zhang 28 male
li 24 female
liu 23 male
wang 21 female
lu 18 male

  

返回的结果很像一张"报表",有"表头"  、"表内容"、  "表尾",这就是awk对文本的格式化能力 

 5.4  BEGIN、END的综合应用实例:统计在文本中匹配到指定字符的次数

[root@weq ~]# cat 123.txt
zs:x:1028:1028::/home/zs:/bin/bash
xx:x:1003:1003::/home/xx:/bin/bash
users.txt:x:1001:1001::/home/users.txt:/bin/bash
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
stu9:x:1015:1015::/home/stu9:/bin/bash
stu8:x:1014:1014::/home/stu8:/bin/bash
stu7:x:1013:1013::/home/stu7:/bin/bash
[root@weq ~]# awk 'BEGIN{x=0};/\/bin\/bash/ {x++};END{print x;}' 123.txt
6
[root@weq ~]# awk 'BEGIN{x=0};/\/bin\/bash/ {x++;print $0;print x};END{print x;}' 123.txt
zs:x:1028:1028::/home/zs:/bin/bash
1
xx:x:1003:1003::/home/xx:/bin/bash
2
users.txt:x:1001:1001::/home/users.txt:/bin/bash
3
stu9:x:1015:1015::/home/stu9:/bin/bash
4
stu8:x:1014:1014::/home/stu8:/bin/bash
5
stu7:x:1013:1013::/home/stu7:/bin/bash
6
6

  

三、awk的应用二:按字段输出文本

awk -F   指定分隔符

FS∶ 列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与"-F"作用相同

1、在指定分隔符下,输出指定的字段内容

[root@weq ~]# cat 123.txt
zs:x:1028:1028::/home/zs:/bin/bash
xx:x:1003:1003::/home/xx:/bin/bash
tcpdump:x:72:72::/:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
stu9:x:1015:1015::/home/stu9:/bin/bash
stu8:x:1014:1014::/home/stu8:/bin/bash
stu7:x:1013:1013::/home/stu7:/bin/bash
[root@weq ~]# awk -F ':' '{print $1,$3}' 123.txt
zs 1028
xx 1003
tcpdump 72
sync 5
stu9 1015
stu8 1014
stu7 1013
[root@weq ~]# awk -F ':' '$3<100 {print $1,$3}' 123.txt
tcpdump 72
sync 5
[root@weq ~]# awk -F ':' '!($3<1010) {print $1,$3}' 123.txt
zs 1028
stu9 1015
stu8 1014
stu7 1013

  

2、awk结合if语句,输出指定的字段内容

[root@weq ~]# cat 123.txt
zs:x:1028:1028::/home/zs:/bin/bash
xx:x:1003:1003::/home/xx:/bin/bash
tcpdump:x:72:72::/:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
stu9:x:1015:1015::/home/stu9:/bin/bash
stu8:x:1014:1014::/home/stu8:/bin/bash
stu7:x:1013:1013::/home/stu7:/bin/bash
[root@weq ~]# awk 'BEGIN{FS=":"};{if($3>1010){print $1,$3}}' 123.txt
zs 1028
stu9 1015
stu8 1014
stu7 1013

  

3、awk结合三元运算符,输出指定字段的内容

三元运算符的概念及语法

三元运算符其实是很方便很好用的一种条件判断方法,这个方法可以使调用或渲染数据时逐级筛选。不仅如此,如果适当的扩展三元运算符的逻辑,这个判断方法还会很好玩,也可以在某种情景下提高代码效率。

(关系表达式) ? 表达式1 : 表达式2;
                       True  :  False

int x = 10;
int y = 5;
int z;
如果x大于y 则是true,将x赋值给z;
如果x不大于y 则是false,将y赋值给z;
z = (x > y) ? x : y;
System.out.println("x = " + x);

实例操作格式:   

[root@weq ~]# cat 123.txt
zs:x:1028:1028::/home/zs:/bin/bash
xx:x:1003:1003::/home/xx:/bin/bash
tcpdump:x:72:72::/:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
stu9:x:1015:1015::/home/stu9:/bin/bash
stu8:x:1014:1014::/home/stu8:/bin/bash
stu7:x:1013:1013::/home/stu7:/bin/bash
[root@weq ~]# awk -F ':' '{max=($3>=$4)?$3:$4;{print max}}' 123.txt
1028
1003
72
5
1015
1014
1013

  

4、输出行号以及内容(跟sed输出的行号对比) 

[root@weq ~]# cat users.txt 
weq
xx
ly
lucy
nancy
[root@weq ~]# sed '=' users.txt 
1
weq
2
xx
3
ly
4
lucy
5
nancy
[root@weq ~]# awk '{print NR,$0}' users.txt 
1 weq
2 xx
3 ly
4 lucy
5 nancy

  

5、在指定分隔符下,输出包含指定内容的字段内容

[root@weq ~]# cat 123.txt
zs:x:1028:1028::/home/zs:/bin/bash
xx:x:1003:1003::/home/xx:/bin/bash
tcpdump:x:72:72::/:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
stu9:x:1015:1015::/home/stu9:/bin/bash
stu8:x:1014:1014::/home/stu8:/bin/bash
stu7:x:1013:1013::/home/stu7:/bin/bash
[root@weq ~]# awk -F ':' '$7~"/sbin" {print $1,$7}' 123.txt
tcpdump /sbin/nologin
[root@weq ~]# awk -F ':' '($1~"stu")&&($7~"/bin"){print $1,$7}' 123.txt
stu9 /bin/bash
stu8 /bin/bash
stu7 /bin/bash
[root@weq ~]# awk -F ':' '($1!~"stu")&&($7!~"/bin"){print $1,$7}' 123.txt
tcpdump /sbin/nologin

  

四、awk的应用三:通过管道、双引号调用shell命令

 

echo $PATH | awk 'BEGIN{RS=":"};END{print NR}'   #统计以冒号分隔的文本段落数,END{}语句块中,往往会放入打印结果等语句

awk -F: '/bash$/{print | "wC -1"}' /etc/passwd   #调用wc -1命令统计使用bash 的用户个数,等同于grep -c "bash$" /etc/passwd

free -m | awk '/Mem:/ {print int($3/($3+$4)*100)"%"}'  #查看当前 内存使用百分比

top -b -n 1| grep Cpu | awk-F ',' '{print$4}'| awk '{print$1}'   #查看当前CPU空闲率,(-b-n 1 表示只需要1次的输出结果)

date -d "$ (awk -F "." '{print $1}' /proc/uptime) second ago" +"%F %H: %M: %S"     #显示上次系统重启时间,等同于upt ime; second ago为显示多少秒前的时间,+"%F %H: %M:%S"等同于+"*Y-%m-%d %H:%M:%S"的时间格式

awk 'BEGIN {n=0 ; while ("w" | getline) n++ ; {print n-2}}' #调用w命令,并用来统计在线用户数

awk 'BEGIN {"hostname" | getline ; {print $0}}'  #调用hostname, 并输出当前的主机名

 

1、指定RS: 行分隔符,输出行号和文本;结合wc -l 统计出行数

[root@weq ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@weq ~]# echo $PATH | awk 'BEGIN{RS=":"};{print NR,$0}'
1 /usr/local/sbin
2 /usr/local/bin
3 /usr/sbin
4 /usr/bin
5 /root/bin

[root@weq ~]# cat 123.txt
zs:x:1028:1028::/home/zs:/bin/bash
xx:x:1003:1003::/home/xx:/bin/bash
tcpdump:x:72:72::/:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
stu9:x:1015:1015::/home/stu9:/bin/bash
stu8:x:1014:1014::/home/stu8:/bin/bash
stu7:x:1013:1013::/home/stu7:/bin/bash
[root@weq ~]# awk -F ':' '/bash$/ {print | "wc -l"}' 123.txt
5
[root@weq ~]# awk -F ':' '/bash$/ {print}' 123.txt
zs:x:1028:1028::/home/zs:/bin/bash
xx:x:1003:1003::/home/xx:/bin/bash
stu9:x:1015:1015::/home/stu9:/bin/bash
stu8:x:1014:1014::/home/stu8:/bin/bash
stu7:x:1013:1013::/home/stu7:/bin/bash
[root@weq ~]# grep -c "bash$" 123.txt
5
awk -F ':' '/bash$/ {print | "wc -l"}' 123.txt     等同于   grep -c "bash$" 123.txt

  

2、查看内存使用情况,并输出内存使用百分比

[root@weq ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:           1823         250        1106           9         465        1387
Swap:          4095           0        4095
[root@weq ~]# free -m | awk '/Mem:/ {print int($3/$2*100)"%"}'
13%

  

3、查看当前CPU空闲率,(-b-n 1 表示只需要1次的输出结果)

[root@weq ~]# top -b-n 1 | awk '/%Cpu/ {print $0}' 
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
[root@weq ~]# top -b-n 1 | awk -F',' '/%Cpu/ {print $4}' | awk '{print $1}' 
93.8
[root@weq ~]# top -b-n 1 | awk -F',' '/%Cpu/ {print $4}' | awk '{print int($1)"%"}' 
93%

  

4、显示上次系统重启时间,等同于uptime; second ago为显示多少秒前的时间,+"%F %H: %M:%S"等同于+"*Y-%m-%d %H:%M:%S"的时间格式

4.1   /proc/uptime解析

[root@weq ~]# cat /proc/uptime 
204.99 189.78  

第一列输出的是,系统启动到现在的时间(以秒为单位),这里简记为num1;
第二列输出的是,系统空闲的时间(以秒为单位),这里简记为num2。

系统的空闲率(%) = num2/(num1*N) 其中N是SMP系统中的CPU个数。  

4.2 uptime解析

系统当前时间

系统已经运行了多长时间

目前有多少登陆用户

系统在过去的1分钟 5分钟 15分钟内的平均负载。

你可以使用 w 命令来代替 uptime。w 也提供关于当前系统登录用户和用户所进行工作的相关信息。  

[root@weq ~]# uptime 
 09:11:03 up 2 min,  1 user,  load average: 0.02, 0.03, 0.02
[root@weq ~]# cat /proc/uptime 
204.99 189.78
[root@weq ~]# w
 09:17:55 up 9 min,  1 user,  load average: 0.00, 0.01, 0.02
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/1    192.168.229.1    09:08    3.00s  0.01s  0.00s w

4.3  实例操作格式

date  -d<字符串>:显示字符串所指的日期与时间。字符串前后必须加上双引号;

[root@weq ~]# cat /proc/uptime 
731.96 715.63
[root@weq ~]# awk -F '.' '{print $1}' /proc/uptime 
813
[root@weq ~]# date -d "$(awk -F '.' '{print $1}' /proc/uptime)second ago" +"%F %H:%M:%S"
2021-07-29 09:08:22  

4.4 输出结果  

  

5、调用w命令,并用来统计在线用户数

 5.1  getline详解

getline是从流中获取一行信息输入到字符串中:

当getline左右无重定向符“<”或“|”时,awk首先读取到了第一行,就是1,然后getline, 就得到了1下面的第二行,就是2,因为getline之后,awk会改变对应的NF, NR,FNR和$0等 内部变量,所以此时的$0的值就不再是1,而是2了,然后将它打印出来。

当getline左右有重定向符“<”或“I”时,getline则作用 于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入那么getline返回的是该文件的第一行, 而不是隔行。

[root@weq ~]# seq 10
1
2
3
4
5
6
7
8
9
10
[root@weq ~]# seq 10 | awk '{getline;print $0}'
2
4
6
8
10
[root@weq ~]# seq 10 | awk '{print $0;getline}'
1
3
5
7
9

回顾:seq的概念

seq(squeue) 是一个序列的缩写,主要用来输出序列化的东西

用法: seq[选项]... 尾数

        seq[选项]... 首数 尾数

        seq[选项]... 首数 增量 尾数

以指定增量从首数开始打印数字到尾数  

5.2  FNR 与NR的概念

FNR:awk当前读取的记录数,其变量值小于等于NR(比如当读取第二个文件时,FNR是从0开始重新计数,而NR不会)。
NR==FNR:用于在读取两个或两个以上的文件时,判断是不是在读取第一个文件

5.3 实例操作格式

[root@weq ~]# w
 09:42:39 up 34 min,  4 users,  load average: 0.00, 0.01, 0.02
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/1    192.168.229.1    09:08    7.00s  0.05s  0.00s w
root     pts/0    192.168.229.1    09:42   27.00s  0.02s  0.02s -bash
root     pts/2    192.168.229.1    09:42    6.00s  0.02s  0.02s -bash
root     pts/3    192.168.229.1    09:42    5.00s  0.01s  0.01s -bash
[root@weq ~]# awk 'BEGIN {n=0;while("w"|getline) n++;{print n-2}}'
4

5.4 输出结果  

 

6、OFS详解

OFS表示输出时可设置改变分割符

  • $1=$1是用来激活$0的重新赋值,也就是说
  • 字段$1…和字段数NF的改变会促使awk重新计算$0的值,通常是在改变OFS后而需要输出$0时这样做
[root@weq ~]# echo 11 22 33 44 | awk 'BEGIN{OFS="|"};{print $0}'
11 22 33 44
[root@weq ~]# echo 11 22 33 44 | awk 'BEGIN{OFS="|"};{$1=$1;print $0}'
11|22|33|44
[root@weq ~]# echo 11 22 33 44 | awk 'BEGIN{OFS="|"};{$2=$2;print $0}'
11|22|33|44
[root@weq ~]# echo 11 22 33 44 | awk 'BEGIN{OFS="|"};{NF=NF;print $0}'
11|22|33|44

  

7、使用awk结合for循环遍历创建数组

[root@weq ~]# awk 'BEGIN{a[0]=10;a[1]=20; print a[1]}'
20
[root@weq ~]# awk 'BEGIN{a["aaa"]=10;a["bbb"]=20; print a["aaa"]}'
10
[root@weq ~]# awk 'BEGIN{a[0]=10;a[1]=20; for(i in a){print i}}'
0
1
[root@weq ~]# awk 'BEGIN{a["aaa"]=10;a["bbb"]=20; for(i in a){print i}}'
aaa
bbb
[root@weq ~]# awk 'BEGIN{a[0]=10;a[1]=20; for(i in a){print i,a[i]}}'
0 10
1 20
[root@weq ~]# awk 'BEGIN{a["aaa"]=10;a["bbb"]=20; for(i in a){print i,a[i]}}'
aaa 10
bbb 20

  

8、使用awk结合for循环以及sort统计重复的次数并排序

[root@weq ~]# cat testfile7
bc
bc
ab
ab
ab
ab
ab
cd
[root@weq ~]# sort testfile7 | uniq -c
      5 ab
      2 bc
      1 cd
[root@weq ~]# awk '{a[$1]++}END{for(i in a){print i,a[i]}}' testfile7 | sort
ab 5
bc 2
cd 1

注意:a[$1]初始为0,a[$1]++后即为1,而这里awk中的a[$1]++的最终值由该文本中内容有多少行决定的,文本逐行读取完毕,再执行END中的命令  

   

posted on 2021-07-29 11:03  笑洋仟  阅读(542)  评论(0编辑  收藏  举报

levels of contents