linux进阶-文本三剑客之AWK-实战案例

文章目录

  • 实验一:awk基本用法
    • awk工作原理
    • awk基本用法
    • 基本格式
    • 分隔符、域、记录
      • 范例
  • 实验二:变量用法
    • 内置变量
      • 1.awk的内建变量使⽤
      • 2.awk的⾃定义变量使⽤
  • 实验三:awk格式化输出
    • 格式输出格式:printf "FORMAT", item1, item2,...
    • 格式符:与item一一对应
    • 修饰符
      • 1.printf命令:格式化输出
  • 实验四:awk的操作符
    • 算数操作符
    • 赋值操作符
    • 比较操作符
    • 模式匹配符
    • awk pattern:awk的模式
    • awk action:常用的action分类
    • 逻辑操作符
      • 1.awk使⽤算术操作符
      • 2.awk赋值操作符
      • 3.awk中的模式匹配符
      • 4.awk的逻辑操作符
      • 5.awk的PATTERN使⽤
      • 6.BRGIN/END模式
  • 实验五:awk的条件判断
    • 控制语句
      • 1.awk条件表达式的使⽤
      • 2.awk组合语句
      • 3.if-else语句:对awk取得的整⾏或某字段做条件判断
  • 实验六:awk的循环
    • 使⽤场景:对⼀⾏内的多个字段逐⼀类似处理时使⽤;对数组中的各元素逐⼀处理时使⽤。
    • which语句
    • break、continue、next语句:
      • 1.awk中使⽤while循环
      • 2.awk中使⽤do-while循环
      • 3.awk中使⽤for循环
      • 4.性能⽐较
      • 5.continue语句
      • 6.break语句
      • 7.next语句
  • 实验七:awk的数组
    • 掌握awk中的数组
      • 1、awk中数组
      • 2.在awk中使⽤for循环遍历数组中的每个元素
  • 实验⼋:awk的函数
    • 数值处理:
    • 字符串处理:
    • ⾃定义函数:
      • 1、rand()函数:⽣成随机数
      • 2.length()函数:统计字符长度
      • 3.sub()函数:替换第⼀次匹配的字符
      • 4.gsub()函数:全部替换
      • 5.split()函数:指定分隔符,分隔字符串
      • 6.⾃定义函数
  • 实验九:awk调⽤系统命令和其他功能
    • system命令;
    • awk的其他功能:
    • 向awk脚本传递参数
      • 1.使⽤system()函数调⽤linux命令
      • 2.awk脚本
      • 3.给awk脚本传递参数
  • 实验九:awk调⽤系统命令和其他功能
    • system命令;
    • awk的其他功能:
    • 向awk脚本传递参数
      • 1.使⽤system()函数调⽤linux命令
      • 2.awk脚本
      • 3.给awk脚本传递参数

实验一:awk基本用法

awk工作原理

第一步:执记录BEGIN{action;...}语句块中的语句。
第二步:从文件或标准输入(stdin)读取一记录,然后执记录pattern{action;...}语句块,它逐记录扫描文件,从
第一记录到最后一记录重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执记录END{action;...}语句块。
BEGIN语句块在awk开始从输入流中读取记录之前被执记录,这是一个可选的语句块,比如变量初始化、打印输出表格
的表头等语句通常可写在BEGIN语句块中。
END语句块在awk从输入流中读完所有的记录之后被执记录,比如打印所有记录的分析结果这类信息汇总都是在END语句
块中完成,它也是一个可选语句块。
pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执记录
{print},即打印每一个读取到的记录,awk读取的每一记录都会执记录该语句块。
print格式:print item1, item2, ...

注意

逗号分隔符;
输出的各item可以是字符串,也可是数值;当前记录的字段、变量或awk的表达式;
如省略item,相当于print $0。

awk基本用法

awk [options] 'program' var=value file ...
awk [options] -f programfile var=value file ...
awk [options] 'BEGIN{ action;...} pattern{ action;... } END{ action;... }' file ...

基本格式

awk [options] 'program' file
program:表示为pattern{action statements;...}
pattern:表示部分决定动作语句何时触发及触发事件BEGIN、END;
action statements:表示对数据进记录处理,放置{}内指明print、printf。

分隔符、域、记录

awk执记录时,由分隔符的字段(域)标记$1,$2...$n称为域标识。$0为所有域,注意:和shell中变量$符含义不
同;
文件的每一记录称为记录;
省略action,则默认执记录print $0的操作。

范例

awk省略action,默认执⾏print $0

[root@localhost data]# awk '{print}' awktest.txt 
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
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

指定:(冒号)为分隔符,打印每⾏记录的第⼀个字段即输出$1

[root@localhost data]# awk -F: '{print $1}' awktest.txt 
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator

同理再把第三个字段输出,输出前添加三个连字符(—):

[root@localhost data]# awk -F: '{print $1"---"$3}' awktest.txt 
root---0
bin---1
daemon---2
adm---3
lp---4
sync---5
shutdown---6
halt---7
mail---8
operator---11

取出磁盘使⽤率

[root@localhost data]# df | grep "/dev/sd" | awk  '{print $5}'
5%
1%
17%

BEGIN的使⽤:

[root@localhost data]# awk '{print 2.5*3}' awktest.txt 
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
[root@localhost data]# awk 'BEGIN{print 2.5*3}' awktest.txt 
7.5
[root@localhost data]# awk 'BEGIN{print 2.5*3}'
7.5

实验二:变量用法

内置变量

FS:输入自动分隔符,默认为空白字符;
OFS:输出自动分隔符,默认为空白字符;
RS:输入记录分隔符,指定输入时的换记录符,原换记录符仍有效;
ORS:输出记录分隔符,输出时用指定符号代替换记录符;
NF:字段数量;
NR:记录号;
FNR:各文件分别计数,记录号;
FILENAME:当前文件名;
ARGC:命令记录参数的个数;
ARGV:数组,保存的是命令记录所给定的各参数。

1.awk的内建变量使⽤

以分号作为分隔符,取1,3;列

[root@localhost data]# awk -v FS=":" '{print $1,FS,$3}' awktest.txt
root : 0
bin : 1
daemon : 2
adm : 3
lp : 4
sync : 5
shutdown : 6
halt : 7
mail : 8
operator : 11

以分号作为分隔符,取1,3,7列 输出时以—作为分隔符

[root@localhost data]# awk -v FS=':' -v OFS='---' '{print $1,$3,$7}' awktest.txt
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

读取文件第一记录,以:作为记录分隔符(通常一记录称为一条记录)

[root@localhost data]# head -1 awktest.txt | awk -v RS=':' '{print}'
root
x
0
0
root
/root
/bin/bash

输出时以—代替换记录符

[root@localhost data]# awk -v ORS='---' '{print}' awktest.txt
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---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---

以:作为分隔符,显示每记录有多少字段

[root@localhost data]# awk -F: '{print NF}' awktest.txt 
7
7
7
7
7
7
7
7
7
7

以:作为分隔符,打印出每记录倒数第二的字段

[root@localhost data]# awk -F: '{print $(NF -1)}' awktest.txt 
/root
/bin
/sbin
/var/adm
/var/spool/lpd
/sbin
/sbin
/sbin
/var/spool/mail
/root

打印文件记录号,且以:作为分隔符取第一个字段

[root@localhost data]# awk -F: '{print NR,$1}' awktest.txt 
1 root
2 bin
3 daemon
4 adm
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 operator

分别为每个各文件添加记录号即记录号

[root@localhost data]# awk '{print FNR,$1}' /etc/fstab /data/awktest.txt 
1 
2 #
3 #
4 #
5 #
6 #
7 #
8 #
9 UUID=cd2bff96-2cf9-4140-8d08-b1a26f2f5059
10 UUID=5f1115c9-0c0b-4e1c-a31d-35d4fd099b05
11 UUID=fd2a26b4-8caa-42cf-a78b-8372f7cae188
12 UUID=31b99478-3e9f-449a-96af-22213f566f8e
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
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
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 operator:x:11:0:operator:/root:/sbin/nologin

2.awk的⾃定义变量使⽤

显示命令记录给定的参数个数

[root@localhost ~]# awk 'BEGIN{print ARGC}' /etc/fstab /etc/inittab 
3

分别显示命令记录这个数组里的每个参数

[root@localhost ~]# awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/inittab 
awk
[root@localhost ~]# awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/inittab 
/etc/fstab
[root@localhost ~]# awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/inittab 
/etc/inittab

定义变量name=username在打印$1时引用变量结果如下

[root@localhost ~]# awk -F: '{name="username:";print name,$1}' /data/awktest.txt
username: root
username: bin
username: daemon
username: adm
username: lp
username: sync
username: shutdown
username: halt
username: mail
username: operator

还可以将变量定义在花括号里,并且进记录引用

[root@localhost ~]# awk -F: '{name="username:";print name,$1}' /data/awktest.txt
username: root
username: bin
username: daemon
username: adm
username: lp
username: sync
username: shutdown
username: halt
username: mail
username: operator

甚至我们可以shell中定义变量,在awk当中进记录引用

[root@localhost ~]# username="username:";awk -F: -v name=$username: '{print name,$1}' /data/awktest.txt 
username:: root
username:: bin
username:: daemon
username:: adm
username:: lp
username:: sync
username:: shutdown
username:: halt
username:: mail
username:: operator

我们同样可以把awk执记录的命令放进一个文件里面,随后我们可以使用awk -f进记录调用

[root@localhost ~]# echo '{name="sun";age=20;print name,$1,age}' > /data/awkscript
[root@localhost ~]# awk -F: -f /data/awkscript /data/awktest.txt
sun root 20
sun bin 20
sun daemon 20
sun adm 20
sun lp 20
sun sync 20
sun shutdown 20
sun halt 20
sun mail 20
sun operator 20

实验三:awk格式化输出

格式输出格式:printf “FORMAT”, item1, item2,…

格式符:与item一一对应

%c:显示字符的ASCII码;
%d,%i:显示十进制整数;
%e,%E:显示科学计数法数值;
%f:显示为浮点数;
%g,%G:以科学计数法或浮点形式显示数值;
%s:显示字符串;
%u:无符号整数;
%%:显示%自身。

修饰符

#[.#]:第一个#为数字控制显示的宽度,第二个#表示小数点后的精度,如%3.1f;
-:左对齐(默认右对齐),如%-15s;
+:显示数值的正负号,如%+d。

1.printf命令:格式化输出

打印第一个字段,其宽度为20个字符并且换记录,默认是右对齐(%s打印字符)

[root@localhost ~]# awk -F: '{printf "%20s \n",$1}' /data/awktest.txt 
                root 
                 bin 
              daemon 
                 adm 
                  lp 
                sync 
            shutdown 
                halt 
                mail 
            operator

加-为左对齐打印

[root@localhost ~]# 
[root@localhost ~]# awk -F: '{printf "%-20s \n",$1}' /data/awktest.txt 
root                 
bin                  
daemon               
adm                  
lp                   
sync                 
shutdown             
halt                 
mail                 
operator 

打印第三个字符,其宽度为20个字符并且换记录,默认是右对齐(%d,%i打印十进制整数)

[root@localhost ~]# awk -F: '{printf "%20d \n",$3}' /data/awktest.txt 
                   0 
                   1 
                   2 
                   3 
                   4 
                   5 
                   6 
                   7 
                   8 
                  11 

加-为左对齐打印

[root@localhost ~]# awk -F: '{printf "%-20d \n",$3}' /data/awktest.txt 
0                    
1                    
2                    
3                    
4                    
5                    
6                    
7                    
8                    
11

以分号作为分隔符在username:后打印第一个字段然后换记录

[root@localhost ~]# awk -F: '{printf "username:%s\n",$1}' /data/awktest.txt 
username:root
username:bin
username:daemon
username:adm
username:lp
username:sync
username:shutdown
username:halt
username:mail
username:operator

以分号作为分隔符在username:后打印第一个字段,宽度为20个字符左对齐显示,在uid:后打印第三个字段然后换记录

[root@localhost ~]# awk -F: '{printf "username:%-20s uid:%d\n" ,$1,$3}' /data/
awktest.txt 
username:root                 uid:0
username:bin                  uid:1
username:daemon               uid:2
username:adm                  uid:3
username:lp                   uid:4
username:sync                 uid:5
username:shutdown             uid:6
username:halt                 uid:7
username:mail                 uid:8
username:operator             uid:11

实验四:awk的操作符

算数操作符

x+y:加法;
x-y:减法;
x*y:乘法;
x/y:除法;
x^y:幂运算;
x%y:取模(余数)。

赋值操作符

=:右边赋值给左边;
+=:先加,再赋值;
-=:先减,再赋值;
*=:先乘,再赋值;
/=:先除,再赋值;
%=:先取余,再赋值;
^=:先幂运算,再赋值;
++:递增操作;
--:递减操作。

比较操作符

==:判断相等;
!=:判断不等;
>:判断大于;
>=:判断大于等于;
<:判断小于;
<=:判断小于等于。

模式匹配符

~:左边是否和右边匹配包含;
!~:是否不匹配。

awk pattern:awk的模式

pattern:根据pattern条件,过滤匹配的记录,再做处理:
1. 如果未指定:空模式,匹配每一记录;
2. /regular expression/:仅处理能够模式匹配到的记录,需要用//扩起来;
3. relational expression:关系表达式,结果为真,才会被处理;
真:结果为非0值,非空字符串都是真;
假:结果为空字符串或0值都是假。
4. line ranges:记录范围;
startine,endline:/pat1/,/pat2/不支持直接给出数子格式。
5. BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执记录一次;
END{}:仅在文本处理完成之后执记录一次。

awk action:常用的action分类

1. Expression:算术,比较表达式等;
2. Control statuments:if,while等;
3. conmpound statements:组合语句;
4. input statements:
5. output statements:print等。

逻辑操作符

&&:逻辑与
||:逻辑或
!:逻辑非

1.awk使⽤算术操作符

使用awk算数操作符,计算2*3

[root@localhost ~]# awk 'BEGIN{print 2*3}'
6

使用awk算数操作符,对5用2取模

[root@localhost ~]# awk 'BEGIN{print 5%2}'
1

2.awk赋值操作符

使用awk的+=赋值操作符

root@localhost ~]# awk 'BEGIN{i=10;print i+=1}'
11

使用awk的i++赋值操作符

[root@localhost ~]# awk 'BEGIN{i=10;print i++;print i}'
10
11

使用awk的++i赋值操作符

[root@localhost ~]# awk 'BEGIN{i=10;print ++i}'
11
[root@localhost ~]# awk 'BEGIN{i=10;print ++i;print i}'
11
11
[root@localhost ~]# awk 'BEGIN{i=10;print ++i,i}'
11 11

3.awk中的模式匹配符

匹配包含root的记录的记录

[root@localhost ~]# awk -F: '$0 ~ /root/{print}' /data/awktest.txt 
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

匹配不包含root的记录的记录

[root@localhost ~]# awk -F: '$0 !~ /root/{print}' /data/awktest.txt 
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

用正则表达式匹配包含root的记录和以root开头的记录

[root@localhost ~]# awk '/root/{print}' /data/awktest.txt 
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# awk '/^root/{print}' /data/awktest.txt 
root:x:0:0:root:/root:/bin/bash

取磁盘利用率

[root@localhost ~]# df -h|grep "/dev/sd"|awk '{print $1,$5}'
/dev/sda2 5%
/dev/sda3 1%
/dev/sda1 17%
[root@localhost ~]# df -h|awk '$0 ~ /^\/dev\/sd/{print $1,$5}'
/dev/sda2 5%
/dev/sda3 1%
/dev/sda1 17%

从hostname.txt⽂件中,提取域名的第⼀部分

[root@localhost ~]# cat /data/hostname.txt 
1 magedu.cn.com
2 www.magedu.com
3 mail.magedu.com
[root@localhost ~]# awk -F'[ |.]' '{print $(NF-2)}' /data/hostname.txt 
magedu
www
mail

4.awk的逻辑操作符

打印第三个字段⼤于等于0,且⼩于等于1000的⾏中的第1字段

[root@localhost ~]# awk -F: '$3>=0 && $3<=1000{print $1}' /data/awktest.txt 
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator

显⽰第三字段等于0,或⼤于等于1000的⾏中的第1字段

[root@localhost ~]# awk -F: '$3==0 || $3>=1000{print $1}' /data/awktest.txt 
root

显⽰除了第三段等于0的⾏中的第1字段

[root@localhost ~]# awk -F: '$3!=0 {print $1}' /data/awktest.txt 
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator

awk实现打印奇数记录和偶数记录

[root@localhost ~]# seq 10 | awk 'i=!i'
1
3
5
7
9
[root@localhost ~]# seq 10 | awk '!(i=!i)'
2
4
6
8
10

等同于sed打印奇数记录和偶数记录

[root@localhost ~]# seq 10 | sed -n '1~2p'
1
3
5
7
9
[root@localhost ~]# seq 10 | sed -n '2~2p'
2
4
6
8
10

5.awk的PATTERN使⽤

打印/etc/passwd文件中以r开头的的记录的第1个和第3个字段

[root@localhost ~]# awk -F: '/^r/{print $1,$3}' /etc/passwd
root 0
rpc 32
rtkit 172
radvd 75
rpcuser 29

查找netstat -nt命令的结果中Foreign Address列的地址,并显⽰

[root@localhost ~]# netstat -nt|awk '/^tcp/{print $5}'|awk -F: '{print $1}'
172.20.1.11

查找netstat -nt命令的结果中Foreign Address列的地址,统计每个地址链接的次数

[root@localhost ~]# awk '/^f/,/^r/' /etc/passwd
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:996:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
colord:x:997:995:User for colord:/var/lib/colord:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin

注意:如果没有⼀r开头的⾏,则会从匹配的以f开头的⾏开始,到最后都显⽰。

6.BRGIN/END模式

awk的BEGIN/END模式的使⽤

[root@localhost ~]# awk -F: 'BEGIN{print "======================="}{printf "%-10s|%10d |\n",$1,$3}END{print "======================="}' /data/awktest.txt 
=======================
root      |         0 |
bin       |         1 |
daemon    |         2 |
adm       |         3 |
lp        |         4 |
sync      |         5 |
shutdown  |         6 |
halt      |         7 |
mail      |         8 |
operator  |        11 |
=======================

实验五:awk的条件判断

控制语句

{statements;...}:组合语句;
if(condition){statements;...}else {statements;...}
if(condition1){statement1}else if(condition2){statement2}
else{statement3}
while(condition){statements;...}
do {statements;...} while(condition)
for(expr1;expr2;expr3) {statements;...}
break
continue
delete array[index]
delete array
exit

1.awk条件表达式的使⽤

显⽰uid⼤于等于500,输出common user,⽤户名和uid,否则输出sysuser

[root@localhost ~]# awk -F: '{$3>=500?usertype="common user":usertype="sysuser";printf "%-15s %-20s %10d\n",usertype,$1,$3}' /etc/passwd 
sysuser         root                          0
sysuser         bin                           1
...
common user     geoclue                     991
sysuser         pulse                       171
common user     saned                       990
sysuser         gdm                          42
common user     gnome-initial-setup         989
sysuser         sshd                         74
sysuser         avahi                        70
sysuser         postfix                      89
sysuser         ntp                          38
sysuser         tcpdump                      72
common user     sun                        1000
common user     apache                      799

查找netstat -nt命令的结果中Foreign Address列的地址,统计每个地址链接的次数,如果⼤于2次,显⽰ip

[root@localhost ~]# netstat -nt|awk '/tcp/{print $4}'|awk -F: '{print $1}'|sort|uniq -c|awk '$1>1{print $2}'

模拟并发访问http服务,查找ip连接次数超过200次的访问ip地址 模拟并发:

[root@localhost ~]# yum -y install httpd-tools
[root@localhost ~]# ab -c 10 -n 200 http://172.20.1.69/

显⽰超过200次访问的ip:

[root@localhost ~]# awk '{print $1}' /var/log/httpd/access_log |sort|uniq -c
    200 172.20.1.69
[root@localhost ~]# awk '{print $1}' /var/log/httpd/access_log |sort|uniq -c|awk '$1>199{print $2}'
172.20.1.69

显⽰第10条到第20条记录的第1字段

[root@localhost ~]# awk -F: '(NR>=10 && NR<=20){print NR,$1}' /etc/passwd
10 operator
11 games
12 ftp
13 nobody
14 systemd-network
15 dbus
16 polkitd
17 libstoragemgmt
18 colord
19 rpc
20 saslauth

注意:显⽰从第10⾏到第20⾏内容,也可⽤sed命令实现:

[root@localhost ~]# sed -n '10,20p' /etc/passwd

2.awk组合语句

以冒号为分隔符,分别打印第1字段和第3字段

[root@localhost ~]# awk  -F: '{print $1;print $3}' /data/awktest.txt 
root
0
bin
1
daemon
2
adm
3
lp
4
sync
5
shutdown
6
halt
7
mail
8
operator
11

3.if-else语句:对awk取得的整⾏或某字段做条件判断

查找/etc/passwd文件中每个记录第三个字段值大于500的记录,并且打印匹配到的每个记录的第一个字段和第三个字段

[root@localhost ~]# awk -F: '{if($3>=500)print $1,$3}' /etc/passwd
polkitd 999
libstoragemgmt 998
colord 997
saslauth 996
setroubleshoot 995
gluster 994
chrony 993
unbound 992
nfsnobody 65534
geoclue 991
saned 990
gnome-initial-setup 989
sun 1000
apache 799

查找/etc/passwd文件中最后一个字段是/bin/bash的记录,打印符合记录的第一个字段

[root@localhost ~]# awk -F: '{if($0 ~ "/bin/bash")print$1}' /etc/passwd
root
sun
apache
[root@localhost ~]# awk -F: '{if($NF=="/bin/bash")print$1}' /etc/passwd
root
sun
apache

查找/etc/fstab文件中每条记录中字段数大于5的记录,并打印该记录

[root@localhost ~]# awk  -F' ' '{if(NR>5)print}' /etc/fstab
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=cd2bff96-2cf9-4140-8d08-b1a26f2f5059 /                       xfs     defaults        0 0
UUID=5f1115c9-0c0b-4e1c-a31d-35d4fd099b05 /boot                   xfs     defaults        0 0
UUID=fd2a26b4-8caa-42cf-a78b-8372f7cae188 /data                   xfs     defaults        0 0
UUID=31b99478-3e9f-449a-96af-22213f566f8e swap                    swap    defaults        0 0

查找第3字段⼤于等500,则输出Common user:第1字段,否则输出root or Sysuer:第1字段
第一种

[root@localhost ~]# awk -F: '{if($3>=500){printf "common user:%s\n",$1} else {printf "root or sysuser:%s\n",$1}}' /etc/passwd

第二种

[root@localhost ~]# awk -F: '{$3>=500?usertype="common user:%s\n":usertype="root or sysuser:%s\n";printf usertype, $1}' /etc/passwd

第三种

[root@localhost ~]# awk -F: '{if($3>=500)printf "common user:%s\n",$1;else printf "root or sysuser:%s\n",$1}' /etc/passwd

显⽰磁盘使⽤率⼤于等于8%的分区

[root@localhost ~]# df -h|awk -F% '/^\/dev\/sd/{print $1}'|awk '$NF>=8{print $1,$5}'
/dev/sda1 17

判断awk⾃定义变量test的值,⼤于90则显⽰very good,⼤于60则显⽰good,其它值显⽰no pass

[root@localhost ~]# read -p "please input one number" NUM; awk -v test=$NUM 'BEGIN{if(test>90){print "very good"}else if(test>60){print "good"}else{print "no pass"}}'

实验六:awk的循环

使⽤场景:对⼀⾏内的多个字段逐⼀类似处理时使⽤;对数组中的各元素逐⼀处理时使⽤。

do-while循环语法:do {statement;...}while(condition)无论真假,至少执行一次循环体。
for循环语法:for(expr1;expr2;expr3){statement;...}
常见用法:
for(variable assignment;condition;iteration process
{for-body}
特殊用法:
能够遍历数组中的元素:for(var in array){for-body}

which语句

语法:switch(expresssion){case VALUE1 or /REGEXP/:statement1;case VALUE2 or
/REGEXP2/:statement2;...;default:statement}

break、continue、next语句:

break [n]:结束整个循环默认是最近的一次循环;
continue [n]:跳过本轮循环,执行下一轮循环;
next:提前结束对本行处理而直接进入下一行处理(awk自身循环)。

1.awk中使⽤while循环

统计第5⾏内容中每个单词分别有多少个字符

[root@centos6 ~]# sed -n '5p' /etc/grub.conf >> /data/kernel.test
[root@centos6 ~]# awk '{i=1;while(i<=NF){print $i,length($i);++i}}' /data/kernel.test 
# 1
all 3
kernel 6
and 3
initrd 6
paths 5
are 3
relative 8
to 2
/boot/, 7
eg. 3

查找最⼤数和最⼩数

[root@centos6 data]# cat /data/NUM.txt 
0.234.252.3246.2245.2345.4536.3754.32.345.323.234.3.1
[root@centos6 data]# awk -F. '{min=$1;max=$1;while(i<=NF){if(max<$i)max=$i;if(min>$i)min=$i;i++};print "max:"max,"min:"min}' /data/NUM.txt 
max:4536 min:0

或使⽤shell命令实现:

[root@centos6 data]# for i in `tr '.' ' ' < /data/NUM.txt`;do echo $i ; done | sort -n |head 
0
1
3
32
234
234
252
323
345
2245
[root@centos6 data]# for i in `tr '.' ' ' < /data/NUM.txt`;do echo $i ; done | sort -n | tail -1
4536
[root@centos6 data]# for i in `tr '.' ' ' < /data/NUM.txt`;do echo $i ; done | sort -n | head -1
0

计算1+2+3+…+100的和

[root@centos6 data]# awk 'BEGIN{i=1;sum=0;while(i<=100){sum+=i;i++};print "sun="sum}'
sun=5050
[root@centos6 data]# read -p "please input one number :" NUM;awk -v num=$NUM 'BEGIN{i=1;sum=0;while(i<=num){sum+=i;i++};print "sum="sum}'

用shell脚本实现

[root@centos6 data]# 
[root@centos6 data]# sum=0;for i in {1..100};do let sum+=i;done;echo sum=$sum
sum=5050

2.awk中使⽤do-while循环

使⽤do-while计算100000内的和

[root@centos6 data]# awk 'BEGIN{total=0;i=0;do{total+=i;i++}while(i<=100);print total}'
5050

3.awk中使⽤for循环

计算100内整数的和

[root@centos6 data]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i};print sum}'
5050

4.性能⽐较

[root@centos6 data]# time (awk 'BEGIN{total=0;i=0;do{total+=i;i++;}while(i<=100000);print total}')
5000050000

real	0m0.011s
user	0m0.010s
sys	0m0.001s
[root@centos6 data]# time ( sum=0;for i in {1..100000};do let sum+=i;done;echo sum=$sum )
sum=5000050000

real	0m0.779s
user	0m0.528s
sys	0m0.250s
[root@centos6 data]# time ( seq -s "+" 100000|bc )
5000050000

real	0m0.107s
user	0m0.110s
sys	0m0.005s
[root@centos6 data]# time(for((i=0;i<=100000;i++));do let total+=i;done;echo $total)
5000050000

real	0m1.041s
user	0m0.908s
sys	0m0.133s

5.continue语句

计算100以内的奇数和

[root@centos6 data]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'
2500

计算100以内的偶数和

[root@centos6 data]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2!=0)continue;sum+=i}print sum}'
2550

6.break语句

计算100内的整数和,但遇到整数66就不计算了,退出执⾏

[root@centos6 data]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}'
2145

7.next语句

显⽰uid为偶数⾏的第1字段和第3字段

[root@centos6 data]# awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
uucp 10
games 12
ftp 14
rpc 32
avahi-autoipd 170
nfsnobody 65534
haldaemon 68
ntp 38
apache 48
saslauth 498
gdm 42
sshd 74
tcpdump 72
sun 500

实验七:awk的数组

掌握awk中的数组

1. 关联数组:array[index-expression]
2. index-expression:
可使用任意字符串;字符串要使用双引号括起来
如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为空串
若要判断数组中是否存在某元素,要使用index in array格式进行遍历
3. 若要遍历数组中的每个元素,要使用for循环
4. for(var in array){for-body}
5. 注意:var会遍历array的每个索引

1、awk中数组

创建⼀个weekdays数组,显⽰索引为mon的数组的中的值

[root@centos6 data]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday

使⽤awk中数组去重

[root@centos6 data]# cat abc.txt
a
b
c
aa
bb
cc
a
b
c
[root@centos6 data]# awk '!arr[$0]++' abc.txt 
a
b
c
aa
bb
cc

去重的思路演⽰

[root@centos6 data]# awk '{!arr[$0]++;print $0,arr[$0]}' /data/abc.txt   用$0作为下标创建数组arr[$0],但是下标为空(为假),取反之后为真,++为其赋值1
a 1 
b 1
c 1
aa 1
bb 1
cc 1
a 2
b 2
c 2

2.在awk中使⽤for循环遍历数组中的每个元素

在awk中创建weekdays数组,并添加两个元素

[root@centos6 data]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesay";for(i in weekdays){print weekdays[i]}}'
Monday
Tuesay

统计netstat -tan命令结果中各个状态的数量
⽣成TIME-WAIT连接:

[root@centos6 data]# ab -c 10 -n 200 http://172.20.1.69/

统计各个tcp状态的个数:

[root@centos6 data]# ss -tan|awk '!/State/{state[$1]++}END{for(i in state){print i,state[i]}}'
ESTAB 1
LISTEN 10

统计httpd的访问⽇志中每个ip访问的次数

[root@magedu ~]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log

统计连接本机的ip地址出现的次数

[root@localhost ~]# ss -nt | awk -F '[ :]+' '!/State/{ip[$(NF-2)]++}END{for(i in ip){print i,ip[i]}}'
172.20.1.11 1

或统计访问次数前⼗的ip地址:

[root@localhost ~]# ss -nt|awk -F '[ :]' '!/State/{ip[$(NF-2)++]}END{for(i in ip){print i,ip[i]}}'|sort -nr -k2|head

查找连接本机的次数⼤于20的ip地址,加⼊到防⽕墙禁⽌连接

[root@magedu ~]# ss -nt | awk -F'[ :]+' '!/State/{ip[$(NF-2)]++}END{for(i in ip){print
i,ip[i]}}' | while read line; do ip=`echo $line | awk '{if($2>20)print $1}'`;[ -z "$ip" ]
|| iptables -A INPUT -s $ip -j REJECT; done

或⽤cut简单简单实现:

[root@magedu ~]# ss -nt | awk -F'[ :]' '!/State/{ip[$(NF-2)]++}END{for(i in ip){print
i,ip[i]}}' |while read line; do num=`echo $line | cut -d" " -f2`; ip=`echo $line | cut -d"
" -f1`;[ $num -gt 3 ] && iptables -A INPUT -s $ip -j REJECT; done
[root@localhost ~]# cat /data/socre,txt 
name sex score
mage  m   100
wang  m   90
li    f   99
zhao  f   95
[root@localhost ~]# awk '!/name/{if($2=="m"){m++;msum+=$3};if($2=="f"){f++;fsum+=$3}}END{print"mavg="msum/m,"favg="fsum/f}' /data/socre,txt 
mavg=95 favg=97

[root@magedu ~]# awk '!/name/{num[$2]++;sum[$2]+=$3}END{for(i in num){print i "
avg="sum[i]/num[i]}}' socre.txt
m avg=95
f avg=97

实验⼋:awk的函数

数值处理:

rand():返回0和1之间的一个随机数,搭配srand()使用
字

字符串处理:

length([s]):返回指定s字符串的长度
sub(r,s[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s
gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2,...

⾃定义函数:

格式:
function name (parameter1, parameter2, ...){
statemenets
return expression
}

1、rand()函数:⽣成随机数

⽣成⼀个0到1之间的随机数

[root@magedu ~]# awk 'BEGIN{print rand()}'
0.237788
[root@magedu ~]# awk 'BEGIN{print rand()}'
0.237788
[root@magedu ~]# awk 'BEGIN{print rand()}'
0.237788
[root@magedu ~]# awk 'BEGIN{srand(); print rand()}'
0.792207
[root@magedu ~]# awk 'BEGIN{srand(); print rand()}'
0.046763
[root@magedu ~]# awk 'BEGIN{srand(); print rand()}'
0.046763

或使⽤shell中⽣成随机数的⽅法:

[root@magedu ~]# echo $RANDOM
8149
[root@magedu ~]# echo $RANDOM
29261
[root@magedu ~]# echo $RANDOM
10121

使⽤awk的循环,⽣成10个0-1之间的随机数

[root@magedu ~]# awk 'BEGIN{srand();for(i=0;i<10;i++)print rand()}'
0.90757
0.89926
0.390811
0.546444
0.441346
0.366411
0.17337
0.301543
0.51216
0.883284

使⽤awk的循环,利⽤int函数⽣成10个整数的随机数

[root@magedu ~]# awk 'BEGIN{srand();for(i=0;i<10;i++)print int(rand()*100)}'
1
68
10
71
94
19
77
23
18
83

2.length()函数:统计字符长度

计算“这是abc”的字符长度

[root@magedu ~]# awk 'BEGIN{print length("这是abc")}'
5

3.sub()函数:替换第⼀次匹配的字符

把第⼀个冒号替换成连字符(-)

[root@magedu ~]# echo "2018:08:17 15:47:50" |awk 'sub(/:/,"-",$1)'
2018-08:17 15:47:50

4.gsub()函数:全部替换

把所有冒号替换成连字符(-)

[root@magedu ~]# echo "2018:08:17 15:47:50" |awk 'gsub(/:/,"-",$0)'
2018-08-17 15-47-50

5.split()函数:指定分隔符,分隔字符串

以冒号为分隔符,分别显⽰每个字段

[root@magedu ~]# echo "2018:08:17 15:47:50" |awk '{split($0,array,":");print array[1]}'
2018
[root@magedu ~]# echo "2018:08:17 15:47:50" |awk '{split($0,array,":");print array[2]}'
08
[root@magedu ~]# echo "2018:08:17 15:47:50" |awk '{split($0,array,":");print array[3]}'
17 15
[root@magedu ~]# echo "2018:08:17 15:47:50" |awk '{split($0,array,":");print array[4]}'
47
[root@magedu ~]# echo "2018:08:17 15:47:50" |awk '{split($0,array,":");print array[5]}'
50

统计连接本机为建⽴状态的ip地址的数量

[root@magedu ~]# netstat -tn|awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in
count){print i,count[i]}}'
172.16.101.234 1

6.⾃定义函数

获得两参数的最⼤值,⾃定义函数,在函数内部参数固定

[root@magedu ~]# cat awk.fn
function max(v1,v2){
v1>v2?var=v1:var=v2
return var
}
BEGIN{a=3;b=2;print max(a,b)}
[root@magedu ~]# awk -f awk.fn
3

获得两参数的最⼤值,根据上例,把参数改为可变动的

[root@magedu ~]# cat awk.fn
function max(v1,v2){
v1>v2?var=v1:var=v2
return var
}
BEGIN{print max(a,b)}
[root@magedu ~]# awk -v a=10 -v b=30 -f awk.fn
30

实验九:awk调⽤系统命令和其他功能

system命令;

空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其
他一律用""引用起来。

awk的其他功能:

将awk程序写成脚本,直接调用或执行

向awk脚本传递参数

格式:awkfile var1=value1 var2=value2 ... Inputfile

注意:在BEGIN过程中不可使⽤,直到⾸⾏输⼊完成以后,变量才可⽤;可通过-v参数,让awk在执⾏BEGIN之前得到变
量的值;命令⾏中每⼀个指定的变量都需要⼀个-v参数。 

1.使⽤system()函数调⽤linux命令

在awk中调⽤linux系统的hostname命令

[root@magedu ~]# hostname
magedu
[root@magedu ~]# awk 'BEGIN{system("hostname")}'
magedu

在awk中使⽤linux中echo命令显⽰awk中的变量

[root@magedu ~]# awk 'BEGIN{score=100;system("echo you score is "score)}'
you score is 100

在awk中使⽤iptables命令拒绝来源地址为1.1.1.1的访问

[root@magedu ~]# awk 'BEGIN{ip="1.1.1.1";system("iptables -A INPUT -s " ip " -j REJECT")}'

2.awk脚本

编写awk脚本,显⽰/etc/passwd中,uid⼤于500的⽤户和uid

[root@magedu ~]# cat f1.awk
#!/bin/awk -f
{if($3>=500)print $1,$3}
[root@magedu ~]# chmod +x f1.awk
[root@magedu ~]# ./f1.awk -F: /etc/passwd
nfsnobody 65534
llj 500
li 501
zhang 502
python 503

3.给awk脚本传递参数

显⽰/etc/passwd⽂件中,uid在10-20之间的⽤户名和uid

[root@magedu ~]# cat f2.awk
#!/bin/awk -f
{if($3>=min && $3<=max)print $1,$3}
[root@magedu ~]# chmod +x f2.awk
[root@magedu ~]# ./f2.awk -F: min=10 max=20 /etc/passwd
uucp 10
operator 11
games 12
gopher 13
ftp 14

或使⽤-v参数指定:

[root@magedu ~]# ./f2.awk -F: -v min=10 -v max=20 /etc/passwd

实验九:awk调⽤系统命令和其他功能

system命令;

空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其
他一律用""引用起来。

awk的其他功能:

将awk程序写成脚本,直接调用或执行

向awk脚本传递参数

格式:awkfile var1=value1 var2=value2 ... Inputfile

注意:在BEGIN过程中不可使⽤,直到⾸⾏输⼊完成以后,变量才可⽤;可通过-v参数,让awk在执⾏BEGIN之前得到变
量的值;命令⾏中每⼀个指定的变量都需要⼀个-v参数。 

1.使⽤system()函数调⽤linux命令

在awk中调⽤linux系统的hostname命令

[root@magedu ~]# hostname
magedu
[root@magedu ~]# awk 'BEGIN{system("hostname")}'
magedu

在awk中使⽤linux中echo命令显⽰awk中的变量

[root@magedu ~]# awk 'BEGIN{score=100;system("echo you score is "score)}'
you score is 100

在awk中使⽤iptables命令拒绝来源地址为1.1.1.1的访问

[root@magedu ~]# awk 'BEGIN{ip="1.1.1.1";system("iptables -A INPUT -s " ip " -j REJECT")}'

2.awk脚本

编写awk脚本,显⽰/etc/passwd中,uid⼤于500的⽤户和uid

[root@magedu ~]# cat f1.awk
#!/bin/awk -f
{if($3>=500)print $1,$3}
[root@magedu ~]# chmod +x f1.awk
[root@magedu ~]# ./f1.awk -F: /etc/passwd
nfsnobody 65534
llj 500
li 501
zhang 502
python 503

3.给awk脚本传递参数

显⽰/etc/passwd⽂件中,uid在10-20之间的⽤户名和uid

[root@magedu ~]# cat f2.awk
#!/bin/awk -f
{if($3>=min && $3<=max)print $1,$3}
[root@magedu ~]# chmod +x f2.awk
[root@magedu ~]# ./f2.awk -F: min=10 max=20 /etc/passwd
uucp 10
operator 11
games 12
gopher 13
ftp 14

或使⽤-v参数指定:

[root@magedu ~]# ./f2.awk -F: -v min=10 -v max=20 /etc/passwd

你可能感兴趣的:(linux进阶,实验专栏)