AWK超详解


问题引入

awk与sed的区别?
awk与sed一样,均是一行一行的读取数据,进行处理的,但不同点在于,sed用作一整行的整理,而awk是将一行分成多个字段来处理的

一、AWK简介

AWK 是一种处理文本文件的语言,是一个强大的文本分析工具,功能十分强大。
之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。

二、使用步骤

1.awk命令使用须知

1. awk的数据字段变量
awk 默认的字段分隔符是任意空白字符(空格或TAB)
$0表示整行文本
$1表示文本中第一个数据字段
$2表示文本中第二个数据字段
$n表示文本中第n个数据字段

2.awk命令的完整语法
awk’BEGIN{commands}pattern{commands}END{commmands}’
命令的执行过程:
BEGIN 只在开始时执行
pattern 每行都要执行
END只在最后执行
3.awk命令的基本语法

awk –F 分隔符 ‘/模式/{动作}’ 文件
awk 的指令一定要用单括号
awk 的动作一定要用花括号
模式可以是正则表达式,条件表达式或两种组合,如果模式是正则表达式要用 / 正则表达式/ 界定符
多个动作之间用;分开

4.awk常用命令选项

-F fs
fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:
-v var=$value
赋值一个用户定义变量,将外部变量传递给awk
-f scripfile
从脚本文件中读取awk命令
5.awk命令的操作符
正则表达式相关符号
数学运算符:+ - * / % ++ –
逻辑运算符:&&(与),||(或),!(非)
比较操作符:> >= < <= != == ~ !~
文本数据表达式:==(精确匹配)
~表示匹配后面的模式,多用正则表达式

6.awk 进行小数的比较和运算

[root@sc-changsha 7-8]# a=6.7
[root@sc-changsha 7-8]# b=7.8
#awk里使用双引号将shell变量传递到awk内部
[root@sc-changsha 7-8]# echo |awk "{if ($a > $b) print 0 ; else print 1 }" 
1
[root@sc-changsha 7-8]# echo |awk "{print $a + $b}" 
14.5
[root@sc-changsha 7-8]# echo |awk "{print $a * $b}"
52.26
[root@localhost ~]# echo |awk "{print 12+12.3}"
24.3
[root@localhost ~]# echo 12.1+223.2|bc
235.3

7.awk命令的内部变量
NF:每行的字段数
NR:当前处理的行号
FS:当前的输入分隔符,默认是空白
OFS:当前的输出分隔符,默认是空白

8.awk命令引用shell变量
-v 引入shell变量

[root@localhost ~]# name=haha
[root@localhost ~]# echo |awk -v var=$name '{print var}'
haha

用双引号“ ”
不使用-v选项,直接使用shell里的变量,使用双引号,花括号里的$符号需要转义

[root@localhost ~]# name=haha
[root@localhost ~]# echo|awk '{print "'$name'"}'
haha
[root@localhost lianxi]# cat /etc/passwd|awk -F: "/$name/ {print \$1,\$2,\$3}"
zwx x 688
zwx1 x 1013
zwx2 x 1014
zwx3 x 1015
zwx4 x 1016
zwx5 x 1017
zwx6 x 1018
zwx7 x 1019
zwx8 x 1020
zwx9 x 1021
zwx10 x 1022
zwxzzz x 7745
zwxzz1 x 7746
zwxztt x 7787
[root@localhost lianxi]# cat /etc/passwd|awk -F: "/$name\>/ {print \$1,\$2,\$3}"
zwx x 688

9.awk内置函数
length()计算字段长度
可以利用length()检查有无空口令用户

[root@localhost ~]# cat /etc/passwd|awk -F: 'length($1)==3 {print $0}'
bin:x:1:1:bin:/bin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
zwx:x:688:7910::/lianxi:/as
zzx:x:1002:1002::/home/zzx:/bin/bash
ass:x:1006:1006::/home/ass:/bin/bash

10.awk基本命令示例

#只有模式没有动作,只有过滤作用,显示整行

[root@localhost /]# awk '/bash/' /etc/passwd

#显示第二个字段

[root@localhost /]# who|awk '{print $2}'
tty1
pts/2
pts/4

#注:who 命令简介:显示目前登入系统的用户信息。如果用户是从一个远程机器登录的,那么该机器的主机名也会被显示出来。

[root@localhost /]# who
root     tty1         2020-07-31 19:28
root     pts/2        2020-08-19 05:48 (192.168.0.25)
root     pts/4        2020-08-19 07:07 (192.168.0.25)

#显示文件中以h开头的行中,以:为分隔符的第1个字段和第7个字段

[root@localhost /]# awk -F: '/^h/ {print $1,$7}' /etc/passwd
halt /sbin/halt
haha /bin/bash

#输出不以h开头的行中,以:为分隔符的第1个字段和第7个字段

[root@localhost /]# awk -F: '/^[^h]/ {print $1,$7}' /etc/passwd

#还可以指定多个分隔符

#未指定分隔符前
[root@localhost /]# awk '/^h/' /etc/passwd
halt:x:7:0:halt:/sbin:/sbin/halt
haha:x:7767:7767::/home/haha:/bin/bash
#指定:/为分隔符号
[root@localhost /]# awk -F '[:/]' '/^h/ {print $1,$10}' /etc/passwd
halt halt
haha bin

如果每行中的第三个字段的长度等于3,则输出该行的第1,3个字段

[root@localhost /]# cat /etc/passwd|awk -F: '$3~/\<...\>/ {print $1,$3}'
systemd-coredump 999
systemd-resolve 193
polkitd 998
unbound 997
sssd 996
rngd 995
zwx 688
nginx 994
sanle 520
saslauth 454
pcp 453

[root@localhost /]# who
root     tty1         2020-07-31 19:28
root     pts/2        2020-08-19 05:48 (192.168.0.25)
root     pts/4        2020-08-19 07:07 (192.168.0.25)
[root@localhost /]# who |awk '{print length($2)}'
4
5
5
[root@localhost /]# who |awk '$2~/\<...\>/{print}'
root     pts/2        2020-08-19 05:48 (192.168.0.25)
root     pts/4        2020-08-19 07:07 (192.168.0.25)

问题:为什么会输出第一行和第三行?
因为单词界定符< > 将/识别成了分隔符,认为pts是一个单词,2或4是一个单词

[root@localhost ~]# who |awk '$2~/\<...\>/ {print}'
root     pts/0        2020-08-21 08:05 (192.168.0.17)
root     pts/1        2020-08-20 21:03 (192.168.0.15)

[root@localhost ~]# who |awk '$2~/\<.\>/ {print}'
root     pts/0        2020-08-21 08:05 (192.168.0.17)
root     pts/1        2020-08-20 21:03 (192.168.0.15)

一个seq产生的1-50的数据序列,如果该数对5取余=0或者该数以1开头,则输出该数

[root@localhost /]# seq 50 |awk '$1%5==0 || $1~/^1/{print $1}'
1
5
10
11
12
13
14
15
16
17
18
19
20
25
30
35
40
45
50

显示UID不等于GID的用户名

[root@localhost ~]# cat /etc/passwd|awk -F: '$3!=$4 {print $1}'

统计使用bash的用户数,并显示这些行

[root@localhost ~]# cat /etc/passwd|awk -F: 'BEGIN{i=0} /bash/ {i++;print $0}END{print "total:"i}'

11AWK内部变量的使用

显示每行及该行的字段数

[root@localhost ~]# cat /etc/passwd|awk -F: '{print $0,NF}'
root:x:0:0:root:/root:/bin/bash 7
bin:x:1:1:bin:/bin:/sbin/nologin 7
daemon:x:2:2:daemon:/sbin:/sbin/nologin 7
adm:x:3:4:adm:/var/adm:/sbin/nologin 7
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 7
sync:x:5:0:sync:/sbin:/bin/sync 7
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 7
halt:x:7:0:halt:/sbin:/sbin/halt 7
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin 7
operator:x:11:0:operator:/root:/sbin/nologin 7

显示每行的第一个字段和最后一个字段

[root@localhost ~]# cat /etc/passwd|awk -F: '{print $1,$NF}'
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
shutdown /sbin/shutdown
halt /sbin/halt
mail /sbin/nologin

显示行号及每行的内容

[root@localhost ~]# cat /etc/passwd|awk -F: '{print NR,$0}'
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

显示文件的第3到第5行

[root@localhost ~]# cat /etc/passwd|awk -F: 'NR==3,NR==5 {print NR,$0}'
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

显示文件的第3和第5行

[root@localhost ~]# cat /etc/passwd|awk -F: 'NR==3 || NR==5 {print NR,$0}'
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

2.AWK进阶部分

1,根据文件批量创建用户,批量删除用户

[root@localhost lianxi]# cat 1.txt
hello 1231
slann 1234
gghdf 1235
[root@localhost lianxi]# awk '{system("useradd "$1)}' 1.txt
[root@localhost lianxi]# ls /home
1.txt  date1.txt  dfgs  gghdf  haha  helly  slann  vmlinuz-0-rescue-f6e57ea094fa4d989de0d0b5f1824c5a  vmlinuz-4.18.0-193.el8.x86_64  xixi
[root@localhost lianxi]# awk '{system("userdel -r "$1)}' 1.txt
[root@localhost lianxi]# ls /home
1.txt  date1.txt  dfgs  haha  vmlinuz-0-rescue-f6e57ea094fa4d989de0d0b5f1824c5a  vmlinuz-4.18.0-193.el8.x86_64  xixi

2,if语句的使用

[root@localhost lianxi]# cat /etc/passwd|awk -F: '{if ($1~/\<...\>/) print $0}'
bin:x:1:1:bin:/bin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
zwx:x:688:7910::/lianxi:/as
zzx:x:1002:1002::/home/zzx:/bin/bash
ass:x:1006:1006::/home/ass:/bin/bash
zaa:x:1007:1007::/home/zaa:/bin/bash
aws:x:1008:1008::/home/aws:/bin/bash

升级版

[root@localhost lianxi]# cat /etc/passwd|awk -F: '{if ($1=="root") print "管理员是:"$1;else if ($1=="ftp") print "ftp用户是:"$1;else print "普通用户是:"$1}'
管理员是:root
普通用户是:bin
普通用户是:daemon
普通用户是:adm
普通用户是:lp
普通用户是:sync
普通用户是:shutdown
普通用户是:halt
普通用户是:mail
普通用户是:operator
普通用户是:games
ftp用户是:ftp

进阶版

[root@localhost lianxi]# awk -F: 'BEGIN{i=0;j=0;k=0;a=""}{if($3==0){i++;a=a" "$1 } else if($3>1 && $3<1000){j++;b=b" "$1;} else {k++;c=c" "$1;}}END{print "管理员:",a," 数量:",i,"\n程序用户:",b,"数量:",j,"\n普通用户:",c,"数量:",k,"\n总共:",i+j+k}'  /etc/passwd

管理员:  root 数量: 1 
程序用户:  daemon adm lp sync shutdown halt mail operator games ftp dbus systemd-coredump systemd-resolve tss polkitd unbound sssd sshd rngd zwx nginx sanle mysql saslauth mailnull smmsp tcpdump named pcp squid 数量: 30 
普通用户:  bin nobody zzx yilin aa as ass zaa aws zssd assds califeng cali123 zwx1 zwx2 zwx3 zwx4 zwx5 zwx6 zwx7 zwx8 zwx9 zwx10 gen chenran zhaiwenxiu sd aq zzz sdf wenlongwang zwxzzz zwxzz1 zwb user01 user02 user03 user04 user05 user06 user07 user08 user09 user10 user11 user12 user13 user15 user16 user17 user18 user19 user20 haha xixi sx1 sx2 sx3 zz1 zzz1 aaa bbb www qqq username aaaa ssss zww zwwa dfgs asas asdfa qqqqq zwxztt zwwxx iii asshjdh 数量: 77 
总共: 108

或者

[root@localhost lianxi]# awk -F: 'BEGIN{super=0;admin=0;user=0;super2="";user2=""}{if($3==0){super=super+1;A[super]=$1}else if($3>=1&&$3<=999){admin=admin+1;B[admin]=$1}else{user=user+1;C[user]=$1}}END{for(k in A){print "管理员是",A[k],",数量是",super};for (k in B){super2=super2" "B[k]};print "程序用户是",super2,".数量是",admin;for (k in C){user2 = user2" "C[k]};print "普通用户是",user2,",数量是",user;print "总共有",admin+super+user,"个用户"}'  /etc/passwd
管理员是 root ,数量是 1
程序用户是  bin daemon adm lp sync shutdown halt mail operator games ftp dbus systemd-coredump systemd-resolve tss polkitd unbound sssd sshd rngd zwx nginx sanle mysql saslauth mailnull smmsp tcpdump named pcp squid .数量是 31
普通用户是  nobody zzx yilin aa as ass zaa aws zssd assds califeng cali123 zwx1 zwx2 zwx3 zwx4 zwx5 zwx6 zwx7 zwx8 zwx9 zwx10 gen chenran zhaiwenxiu sd aq zzz sdf wenlongwang zwxzzz zwxzz1 zwb user01 user02 user03 user04 user05 user06 user07 user08 user09 user10 user11 user12 user13 user15 user16 user17 user18 user19 user20 haha xixi sx1 sx2 sx3 zz1 zzz1 aaa bbb www qqq username aaaa ssss zww zwwa dfgs asas asdfa qqqqq zwxztt zwwxx iii asshjdh ,数量是 76
总共有 108 个用户

经典面试题目

自己编写脚本统计每秒钟ens33网卡的接受和发送数据的流量

[root@localhost lianxi]# watch -n 1 -d "ifconfig ens33|awk 'NR==5||NR==7{print $5}'"

使用awk计算seq 20产生的序列的和

[root@localhost lianxi]# seq 20|awk 'BEGIN{sum=0}{sum+=$1}END{print sum}'
210

如何知道密码为空的用户有哪些?

[root@localhost ~]# cat /etc/shadow|awk -F: '$2~/*|!!/ {print $1}'
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp

简单总结

awk执行结果可以通过print的功能将字段数据打印显示。在使用awk命令中,常用逻辑操作符“&&”和“||”;

awk也可以进行简单的数学运算,如+ 、-、*、/、%、^分别表示加、减、乘、除、取余、乘方,还可以进行小数的运算。

awk还可以进行正则匹配

awk从输入文件或者标准输入中读入信息,与sed一样,信息的读入也是逐行读取的。不同的是,awk命令将文本文件中的一行视为一个记录,而将一行中的某一部分(列)作为记录的一个字段。

为了操作这些不同的字段(列),awk借用shell中类似于位置变量的方法,用$1、$2…$9顺序的表示不同列,$0表示整行。

不同字段与不同字段可以通过指定的方式进行分隔,awk默认的分隔符是空白(空格和TAB)。awk命令允许使用“-F分隔符”的形式来指定分隔符。

命令较多时,可以使用“BEGIN……END” 其中还可以加入if else语句。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值