目录
1.4.2、按单词出现频率降序排序(计算文件中每个单词的重复数量)
2.6.1、第二个作用,在读取文件之前输出写提示性信息,表头
2.6.2、第三种用法,使用BEGIN模块的特殊性质进行测试
2.6.5、统计/etc/services文件里面的空行数量
一、awk简介与使用
1.1、awk讲解
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理,能够对文本进行复杂的格式处理,是一种处理文本的语言,可以进行样式装入、流控制、数学运算、流程控制,还有内置的变量和函数,具备一个完整语言所应具有的几乎所有完美特性,相当于一个小型编程语言。其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。
1.1、查看awk版本
[root@RedHat8-2 ~]# cat /etc/redhat-release
Red Hat Enterprise Linux release 8.2 (Ootpa)
[root@RedHat8-2 ~]# awk --version
GNU Awk 4.2.1, API: 2.0 (GNU MPFR 3.1.6-p2, GNU MP 6.1.2)
Copyright (C) 1989, 1991-2018 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
1.2、awk的格式
awk指令是由模式,动作,或者模式和动作的组合组成,
模式即pattern,可以类似理解成sed的模式匹配,可以有表达式组成,也可以是两个正斜杠之间的正则表达式。比如NR==1,这就是模式,可以把它理解为一个条件。
动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。如下awk使用格式:
awk处理的内容可以来自标准输入(<)一个或多个文本文件或管道
[root@RedHat8-2 ~]# awk -F ":" 'NR<=5{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
####
[root@RedHat8-2 ~]# awk 参数 '条件(找谁){动作(做什么)}' /etc/passwd
pattern即模式,可以理解为条件,以什么条件为例去找?都是条件即模式
action即动作,可以理解为干啥,找到之后要做什么。
1.3、awk执行过程
1.4、记录和字段
下面是两个新概念的记录和字段,为了方便理解可以把记录就当做行即记录==行,字段相当于列,字段==列。
名称 | 含义 |
record | 记录,行 |
field | 域,区域,字段,列 |
创建测试环境:
[root@RedHat8-2 ~]# mkdir /root/test
[root@RedHat8-2 ~]# cd test
[root@RedHat8-2 test]# head /etc/passwd > /root/test/awkfile.txt
1.4.1、记录(行)
awk对每个要处理的输入数据认为都是具有格式和结构的,而不仅仅是一堆字符串。默认情况下,每一行内容都是一条记录,并以换行符(\n)结束。
(1)awk记录分隔符-RS
记录分隔符-每一个记录(行)是如何结束的
- awk默认情况下每一行都是一个记录(record)
- RS即record separator输入数据记录分隔符,每一行是怎么没的,表示每个记录输入的时候的分隔符,即行与行之间如何分隔。
- NR即number of record记录(行)号,表示当前正在处理的记录(行)的号码
- ORS即output record separate输出记录分隔符
awk使用内置变量RS来存放输入记录分隔符,RS表示的是输入的记录分隔符,这个值可以通过BEGIN模块重新定义修改
[root@RedHat8-2 test]# head -2 awkfile.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@RedHat8-2 test]# awk 'BEGIN{RS="/"}{print NR,$0}' awkfile.txt
1 root:x:0:0:root:
2 root:
3 bin
4 bash
bin:x:1:1:bin:
5 bin:
6 sbin
7 nologin
daemon:x:2:2:daemon:
8 sbin:
9 sbin
10 nologin
adm:x:3:4:adm:
....
#以:为每一行的结束
[root@RedHat8-2 test]# awk 'BEGIN{RS=":"}{print NR,$0}' awkfile.txt
#以连续的数字为每一行的结束
[root@RedHat8-2 test]# awk 'BEGIN{RS="[0-9]+"}{print NR,$0}' awkfile.txt
[root@RedHat8-2 test]# awk -v RS="[0-9]+" '{print NR,$0}' awkfile.txt
#awk -v 变量=值(变量是书的名字,值是书的内容)
在awk眼中,文件是从头到尾一段连续的字符串,恰巧中间有些(\n回车换行符),\n也是字符。
\n就是换行,所以后面的内容到了下一行
(2)对$0的认识
如上图可看出awk中$0表是整行,其实awk使用$0来表示整条记录。记录分隔符\n保存在RS变量中。
另外awk对每一行的记录号都有一个内置变量NR来保存,每处理完一条记录NR的值就会自动+1 。
1.4.2、按单词出现频率降序排序(计算文件中每个单词的重复数量)
注:(此处使用sort与uniq即可)
[root@RedHat8-2 test]# sed -r 's#[^a-zA-Z]+# #g' /etc/passwd> /root/count.txt
[root@RedHat8-2 test]# cat /root/count.txt
root x root root bin bash
bin x bin bin sbin nologin
daemon x daemon sbin sbin nologin
adm x adm var adm sbin nologin
lp x lp var spool lpd sbin nologin
sync x sync sbin bin sync
shutdown x shutdown sbin sbin shutdown
halt x halt sbin sbin halt
mail x mail var spool mail sbin nologin
operator x operator root sbin nologin
games x games usr games sbin nologin
ftp x FTP User var ftp sbin nologin
nobody x Kernel Overflow User sbin nologin
dbus x System message bus sbin nologin
systemd coredump x systemd Core Dumper sbin nologin
systemd resolve x systemd Resolver sbin nologin
tss x Account used by the trousers package to sandbox the tcsd daemon dev null sbin nologin
polkitd x User for polkitd sbin nologin
unbound x Unbound DNS resolver etc unbound sbin nologin
sssd x User for sssd sbin nologin
chrony x var lib chrony sbin nologin
sshd x Privilege separated SSH var empty sshd sbin nologin
pesign x Group for the pesign signing daemon var run pesign sbin nologin
rngd x Random Number Generator Daemon var lib rngd sbin nologin
test x home test sbin nologin
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
思路:
- 让所有单词排成一列,这样每个单词都会是单独的一行
- 设置RS值为空格
- 将文件里面的所有空格替换为回车换行符“\n”
整体思路:想办法让所有单词排成一列,站成一排,排序,合并重复的,显示重复数量
[root@RedHat8-2 test]# awk 'BEGIN{RS="[^a-zA-Z]+"}{print $0}' /root/count.txt|sort|uniq -c|sort -rn
35 x
27 sbin
21 nologin
20 stu
15 bin
11 home
11 bash
8 var
4 User
4 systemd
4 root
4 daemon
3 the
3 sync
3 shutdown
3 pesign
3 mail
3 halt
3 games
3 for
3 adm
2 unbound
2 test
2 sssd
2 sshd
2 spool
2 rngd
2 polkitd
2 operator
2 lp
2 lib
2 ftp
2 chrony
1 usr
1 used
1 Unbound
1 tss
1 trousers
1 to
1 tcsd
1 System
1 SSH
1 signing
1 separated
1 sandbox
1 run
1 Resolver
1 resolver
1 resolve
1 Random
1 Privilege
1 package
1 Overflow
1 Number
1 null
1 nobody
1 message
1 lpd
1 Kernel
1 Group
1 Generator
1 FTP
1 etc
1 empty
1 Dumper
1 DNS
1 dev
1 dbus
1 Daemon
1 coredump
1 Core
1 by
1 bus
1 Account
sort :默认是按照 字母顺序排列
-r :倒序
-n :按数字排序
uniq :把重复的合并成一行
-c:显示重复出现的次数
[root@RedHat8-2 test]# awk 'BEGIN{RS=" "}{print $0}' /root/count.txt|sort|uniq -c|sort -rn
35 x
27 sbin
21 nologin
20 stu
15 bin
11 home
11 bash
8 var
4 User
4 systemd
4 root
4 daemon
3 the
3 sync
3 shutdown
3 pesign
3 mail
3 halt
3 games
3 for
3 adm
2 unbound
2 test
2 sssd
2 sshd
2 spool
2 rngd
2 polkitd
2 operator
2 lp
2 lib
2 ftp
2 chrony
1 usr
1 used
1 Unbound
1 tss
1 trousers
1 to
1 tcsd
1 System
1 SSH
1 signing
1 separated
1 sandbox
1 run
1 Resolver
1 resolver
1 resolve
1 Random
1 Privilege
1 package
1 Overflow
1 Number
1 null
1 nobody
1 message
1 lpd
1 Kernel
1 Group
1 Generator
1 FTP
1 etc
1 empty
1 Dumper
1 DNS
1 dev
1 dbus
1 Daemon
1 coredump
1 Core
1 by
1 bus
1 Account
1
一步一步来,先修改了RS,然后用NR调试,看看到底如何分隔的。
然后通过sort排序,uniq去重。
1.4.3、awk记录小结
- NR存放着每个记录的号(行号)读取新行时会自动+1
- RS是输入数据的记录的分隔符,简单理解就是可以指定每个记录的结尾标志
- RS作用就是小事一个记录的结束
- 当我们修改了RS的值,最好配合NR(行)来查看变化,也就是修改了RS的值通过NR查看结果,调试awk程序
- ORS输出数据的记录的分隔符
1.4.4、字段(列)
每条记录都是由多个区域(field)组成的,默认情况下区域之间的分隔符是由空格(即空格或制表符)来分隔,并且将分隔符记录在内置变量FS中,每行记录的区域保存在awk的内置变量NF中。
约定:
field有很多种解释,域,记录,区域。为了方便理解适用区域表示(field)
FS即field separator 输入字段(列)分隔符。把一行字符串切为很多个区域。
NF即number of fileds,表示一行中列(字段)的个数,可以理解为切成了多少份。
OFS使用内置变量FS来记录区域分隔符的内容,FS可以在命令行上通过-F参数来更改,也可以通过BEGIN模块来更改
然后通过$n,n是整数,来取被切割后的区域,$1取第一个区域,$2取第二个区域,$NF取最后一个区域。
实例:
[root@RedHat8-2 ~]# awk '{print NF,$0}' count.txt
6 root x root root bin bash
6 bin x bin bin sbin nologin
6 daemon x daemon sbin sbin nologin
7 adm x adm var adm sbin nologin
8 lp x lp var spool lpd sbin nologin
6 sync x sync sbin bin sync
6 shutdown x shutdown sbin sbin shutdown
6 halt x halt sbin sbin halt
8 mail x mail var spool mail sbin nologin
6 operator x operator root sbin nologin
7 games x games usr games sbin nologin
8 ftp x FTP User var ftp sbin nologin
7 nobody x Kernel Overflow User sbin nologin
7 dbus x System message bus sbin nologin
8 systemd coredump x systemd Core Dumper sbin nologin
7 systemd resolve x systemd Resolver sbin nologin
17 tss x Account used by the trousers package to sandbox the tcsd daemon dev null sbin nologin
7 polkitd x User for polkitd sbin nologin
9 unbound x Unbound DNS resolver etc unbound sbin nologin
7 sssd x User for sssd sbin nologin
7 chrony x var lib chrony sbin nologin
10 sshd x Privilege separated SSH var empty sshd sbin nologin
13 pesign x Group for the pesign signing daemon var run pesign sbin nologin
11 rngd x Random Number Generator Daemon var lib rngd sbin nologin
6 test x home test sbin nologin
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
[root@RedHat8-2 ~]# echo "I am xiao,bai weixin is xxxxxx" >> /test/xiaobai.txt
[root@RedHat8-2 ~]# cd /test/
[root@RedHat8-2 test]# cat xiaobai.txt
I am xiao,bai weixin is xxxxxx
[root@RedHat8-2 test]# awk -F " |," '{print $3,$NF}' xiaobai.txt
xiao xxxxxx
[root@RedHat8-2 test]# awk -F " |," '{print $3","$NF}' xiaobai.txt
xiao,xxxxxx
[root@RedHat8-2 test]# awk -F "[ ,]" '{print $3","$NF}' xiaobai.txt
xiao,xxxxxx
在动作('{print $3,$NF}')中的逗号,表示空格,其实动作中的逗号就是OFS的值,刚开始吧逗号当作空格即可
[root@RedHat8-2 test]# ifconfig ens32|awk 'NR==2{print $1}'
inet
[root@RedHat8-2 test]# ifconfig ens32|awk -F "[ :]+" 'NR==2{print $1}'
[root@RedHat8-2 test]# ifconfig ens32|awk -F "[ :]+" 'NR==2{print $2}'
inet
##awk默认的FS 分隔符 空格序列 一个空格或多个空格 tab 都认为是一样的一个整体
1.4.5、ORS与OFS简介
现在说说ORS和OFS这两个内置变量的含义
RS是输入记录分隔符,决定awk如何读取或分隔每行(记录)
ORS表示输出记录分隔符(output record separator),决定awk如何输出一行(记录)的,默认是回车换行(\n)
FS是输入区域分隔符,决定awk读入一行后如何再分为多个区域
OFS表示输出区域分隔符,决定awk输出每个区域的时候是用什么分隔他们
awk无比强大,可以通过RS,FS决定awk如何读取数据。也可以通过修改ORS,OFS的值指定awk如何输出数据。
例:
调换/etc/passwd中第一列和最后一列位置
[root@RedHat8-2 test]# awk 'BEGIN{FS=":"}{print $NF,$2,$3,$4,$5,$6,$1}' awkfile.txt
/bin/bash x 0 0 root /root root
/sbin/nologin x 1 1 bin /bin bin
/sbin/nologin x 2 2 daemon /sbin daemon
/sbin/nologin x 3 4 adm /var/adm adm
/sbin/nologin x 4 7 lp /var/spool/lpd lp
/bin/sync x 5 0 sync /sbin sync
/sbin/shutdown x 6 0 shutdown /sbin shutdown
/sbin/halt x 7 0 halt /sbin halt
/sbin/nologin x 8 12 mail /var/spool/mail mail
/sbin/nologin x 11 0 operator /root operator
[root@RedHat8-2 test]# awk 'BEGIN{FS=":";OFS=":"}{print $NF,$2,$3,$4,$5,$6,$1}' awkfile.txt
/bin/bash:x:0:0:root:/root:root
/sbin/nologin:x:1:1:bin:/bin:bin
/sbin/nologin:x:2:2:daemon:/sbin:daemon
/sbin/nologin:x:3:4:adm:/var/adm:adm
/sbin/nologin:x:4:7:lp:/var/spool/lpd:lp
/bin/sync:x:5:0:sync:/sbin:sync
/sbin/shutdown:x:6:0:shutdown:/sbin:shutdown
/sbin/halt:x:7:0:halt:/sbin:halt
/sbin/nologin:x:8:12:mail:/var/spool/mail:mail
/sbin/nologin:x:11:0:operator:/root:operator
FS与OFS
awk 'BEGIN{FS=":";OFS="#"}{$1=$1;print $0}' file
这里只是指定了FS和修改OFS,让输出分隔符。
上面的命令也可以写成
awk 'BEGIN{FS=":";OFS="#"}{$1=$1}1' file
RS与ORS
awk 'BEGIN{RS="\n";ORS="#"}{print $0}' file
[root@RedHat8-2 test]# cat >abc.txt<<EOF
> a
> b
> c
> EOF
[root@RedHat8-2 test]# awk 'BEGIN{ORS="xty"}{print $0}' abc.txt
axtybxtycxty[root@RedHat8-2 test]#
(1)RS记录分隔符,表示每行的结束标志
(2)NR行号(记录号)
(3)FS字段分隔符,每列的分割标志或结束标志
(4)NF就是每行有多少列,每个记录中字段的数量
小结:
1) $符号表示取某个列(字段),$1,$2,$NF
2) NF表示记录中的区域(列)数量,$NF取最后一个列(区域)
3) FS(-F)字段(列)分隔符 -F(FS) ":" <==> 'BEGIN{FS=";"}'
4) RS 记录分隔符(行的结束标识)
5) NR行号
6) 选好合适的方式FS(***),RS,OFS,ORS
7) 分隔符==>结束标识
8) 记录与区域,就对我们所谓的行与列,有了新的认识(RS,FS)
二、awk进阶
2.1、awk模式与动作
awk的格式,里面的模式动作,换句话说就是条件和做什么
2.2、正则表达式作为模式
awk同sed一样可以通过模式匹配来对输入的文本进行匹配处理。模式匹配肯定少不了正则表达式,awk也支持大量的正则表达式模式,大部分与sed支持的元字符类似,而且正则表达式是玩转三剑客的必备工具
下面表格列出了awk支持的正则表达式元字符:
元字符 | 功能 | 示例 | 解释 |
^ | 字符串开头 | /^xty/ $3~/^xty/ | 匹配所有以xty开头的字符串 匹配出所有第三列中以xty开头 |
$ | 字符串结尾 | /xty$/ $3~/xty$/ | 匹配所有以xty结尾的(字符串) 匹配第三列中以xty结尾的文本 |
. | 匹配任意单个字符 (包括回车符) | /c..l/ | 匹配字母c,然后两个任意字符,在以l结尾的行 |
* | 重复0个或多个前一个字符 | /a*cool/ | 匹配0个或多个a之后紧跟着cool的行比如:cool、aaacool |
[] | 匹配指定字符内的任一个字符 | /^[abc]/ | 匹配以字母a或b或c开头的行 |
[^] | 匹配不再指定字符组内的任一个字符 | /^[^abc]/ | 匹配不以字母a或b或c开头的行 |
() | 子表达式组合 | /(cool)+/ | 表示一个或多个cool组合,当有一些字符需要组合时,使用括号括起来 |
| | 或者的意思 | /(cool)|B/ | 匹配错了或者字母B的行 |
awk默认不支持的元字符,和需要添加参数才能支持的元字符 | |||
x{m} x{m,} x{m,n} | x重复m次 x重复至少m次 x重复至少m次,但不超过n次 需要指定参数: --posix或者 --re-interval 没有该参数不能使用这种模式 | /cool{5}/ | 需要注意一点的是,cool加括号或不加括号的区别,x可以使字符串也可以是一个字符,所以/cool\{5\}/表示匹配coo在加上5个l,及coolllll, /\(cool\)\{2,\}/则表示匹配coolcoolcoolcool等 |
/(cool){2,}/ | |||
/(cool){5,6}/ | |||
|
2.2.1、awk正则表达式匹配操作符
awk正则匹配操作符
~:用于对记录或区域的表达式进行匹配
!~:用于表达与~相反的意思
2.2.2、awk正则表达式匹配行
[root@RedHat8-2 test]# awk -F ":" '/^root/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
和下面的效果是一样的
[root@RedHat8-2 test]# awk -F ":" '$0~/^root/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
说明:
awk只用正则表达式的时候默认匹配整行的即'$0~/^root/'与'/^root/'是一样的
[root@RedHat8-2 ~]# awk '$3~/c/' count.txt
sync x sync sbin bin sync
tss x Account used by the trousers package to sandbox the tcsd daemon dev null sbin nologin
[root@RedHat8-2 ~]# awk '$3~/c$/' count.txt
sync x sync sbin bin sync
[root@RedHat8-2 ~]# awk '/c$/' count.txt
sync x sync sbin bin sync
[root@RedHat8-2 ~]# awk '$0~/c$/' count.txt
sync x sync sbin bin sync
2.3、练习
cat >/root/test/test.txt<<EOF
zhao yi 536489 50:100:30
qian er 125489 70:200:50
sun san 894563 60:50:30
li si 584965 80:90:5
zhou wu 224587 10:50:80
wu liu 336945 90:30:40
zheng qi 154785 70:60:50
wang ba 987452 40:10:70
EOF
## 第一列是姓氏
## 第二列是名字
## 第一第二列合起来就是姓名
## 第三列是对应的ID号码
## 最后三列是三次充值金额
练习1:显示zhao姓第二次充值金额和姓名
[root@RedHat8-2 test]# awk -F "[ :]+" '/^zhao/{print $2,$5}' test.txt
yi 100
[root@RedHat8-2 test]# awk -F "[ :]+" '/^zhao/{print $1$2,$5}' test.txt
zhaoyi 100
[root@RedHat8-2 test]# awk 'BEGIN{FS="[ :]+"}$1~/^zhao/{print $1$2,$5}' test.txt
zhaoyi 100
[root@RedHat8-2 test]# awk -F "[ :]+" '/^zhao/{print $1$2,$(NF-1)}' test.txt
zhaoyi 100
说明:
-F指定分隔符,-F即FS支持正则表达式
[ :]+ 表示连续空格或冒号
-F "[ :]+" 已连续冒号空格为分隔符
/^zhao/表示条件
{print $1$2,$(NF-1)}表示动作,满足条件后,执行显示第一列($1)和单数第二列($(NF-1))也可以
注意:
NF 是一行中有多少列,NF-1 整行就是倒数第二列
$(NF-1)就是取倒数第二列的内容
练习2:显示liu的姓氏和ID号
[root@RedHat8-2 test]# awk '/liu/{print $1,$3}' test.txt
wu 336945
[root@RedHat8-2 test]# awk '$2~/^liu$/{print $1,$3}' test.txt
wu 336945
说明:
$2~/liu/表示条件,第二列包含liu时候执行对应的动作
{print $1,$3}表示动作,显示第一列和第三列的内容
练习3:显示所有以5开头的ID号码的人全名和ID号码
[root@RedHat8-2 test]# awk '$3~/^5/{print $1$2,$3}' test.txt
zhaoyi 536489
lisi 584965
说明:
$3~/^5/是一个条件,表示匹配第三列以41开头的。满足条件后显示出第一列第二列和第三列的内容
练习4:显示所有以一个s或l开头的名全名
[root@RedHat8-2 test]# awk '$2~/^[sl]/{print $1,$2}' test.txt
sun san
li si
wu liu
[root@RedHat8-2 test]# awk '$2~/^(s|l)/{print $1,$2}' test.txt
sun san
li si
wu liu
说明:
条件:$2~/^(s|l)/
这里^(s|l)表示,以s或l开头的文本(字符串)
同时s或者l也可以使用括号表达式来实现,因为两个字母所有括号表达式也可以[sl]表示s或者l
练习5:显示所有ID号码最后以为数字是2或3的人全名
[root@RedHat8-2 test]# awk '$3~/[23]$/{print $1$2}' test.txt
sunsan
wangba
[root@RedHat8-2 test]# awk '$3~/[23]$/{print $1,$2}' test.txt
sun san
wang ba
[root@RedHat8-2 test]# awk '$3~/(2|3)$/{print $1,$2}' test.txt
sun san
wang ba
练习6:显示er的充值,每个值以¥开头
[root@RedHat8-2 test]# awk -F "[ :]+" '$2~/^er$/{print "¥"$4,"¥"$5,"¥"$6}' test.txt
¥70 ¥200 ¥50
[root@RedHat8-2 test]# awk -F "[ :]+" -v OFS="¥" '$2~/^er/ {print "",$4" ",$5" ",$6}' test.txt
¥70 ¥200 ¥50
[root@RedHat8-2 test]# awk '$2~/^er$/{gsub(/:/,"$",$NF);print "$"$NF}' test.txt
$70$200$50
[root@RedHat8-2 test]# awk -F "[ :]+" '$2~/er/{print "¥"$4"¥"$5"¥"$6}' test.txt
¥70¥200¥50
[root@RedHat8-2 test]# awk '$2~/^er$/{gsub(/:/,"¥");print "¥"$NF}' test.txt
70¥200¥50
[root@RedHat8-2 test]# awk '$2~/^er$/{gsub(/:/,"¥",$NF);print "¥"$NF}' test.txt
¥70¥200¥50
说明:
动作部分是会常用到的拼接,print表示输出内容如果后面的内容有双引号,则双引号里面的内容原封不动输出。
练习7:显示所有人全名,以姓名格式无空格
[root@RedHat8-2 test]# awk '{print $1""$2}' test.txt
zhaoyi
qianer
sunsan
lisi
zhouwu
wuliu
zhengqi
wangba
[root@RedHat8-2 test]# awk -v OFS="," '{print $1$2}' test.txt
zhaoyi
qianer
sunsan
lisi
zhouwu
wuliu
zhengqi
wangba
2.4、比较表达式作为模式
awk是一种编程语言,能够进行更为复杂的判断,当条件为真时候,awk就执行相关的action。主要是在针对某一区域做出相关的判断,比如打印成绩在80以上的行,这样就必须对这一区域作比较判断,下表列出了awk可以使用的关系运算符,可以用来比较数字者字符串,还有正则表达式。当正则表达式为真时候,表达式结果为1,否之为0,只有表达式为真,awk才执行相关的action。
运算符 | 含义 | 示例 |
< | 小于 | x>y |
<= | 小于或等于 | x<=y |
== | 等于 | x==y |
!= | 不等于 | x!-y |
>= | 大于或等于 | x>=y |
> | 大于 | x<y |
以上的运算符均是针对数字,下面两个运算符之前已有示例,针对字符串 | ||
~ | 于正则表达式匹配 | x~/y/ |
!~ | 与正则表达式不匹配 | x!~y |
例:
[root@RedHat8-2 test]# awk -F "[ :]+" '$5>100' test.txt
qian er 125489 70:200:50
[root@RedHat8-2 test]# awk -F "[ :]+" 'NR>=2&&NR<=5' test.txt
qian er 125489 70:200:50
sun san 894563 60:50:30
li si 584965 80:90:5
zhou wu 224587 10:50:80
[root@RedHat8-2 test]# awk -F "[ :]+" 'NR>=2 && NR<=5' test.txt
qian er 125489 70:200:50
sun san 894563 60:50:30
li si 584965 80:90:5
zhou wu 224587 10:50:80
例:
[root@RedHat8-2 test]# awk -F: '$5=="root"' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@RedHat8-2 test]# awk -F: '$5~/^root$/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@RedHat8-2 test]# awk -F: '$5==root' awkfile.txt
[root@RedHat8-2 test]# #awk中 所有的字母 awk会认为是变量
2.5、范围模式
pattern1 | , | pattern2 |
从哪里来 | 到 | 哪里去 |
条件1 | , | 条件2 |
范围模式简单理解就是从哪里来,到哪里去。
匹配从条件1开始到条件2介绍的范围
awk的范围模式,与sed类似,但是又有不同,awk不能直接使用行号来作为范围起始地址,因为awk具有内置变量NR来存储记录号,所有需要使用NR=1,NR=5这样来使用。
范围模式处理原则是:先匹配从第一个模式的首次出现到第二个模式的首次出现之间的内容,执行action。然后匹配从第一个模式的下一次出现到第二个模式的下一次出现,直到文本结束。如果匹配到第一个模式而没有匹配到第二个模式,则awk处理从第一个模式开始直到文本结束全部行,如果第一个模式不匹配,就算第一个模式匹配,awk依旧不处理任何行。
[root@RedHat8-2 test]# awk 'NR==2,NR==5' awkfile.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
[root@RedHat8-2 test]# #范围条件/范围模式
2.5.1、BEGIN模块
BEGIN模块在awk读取文件之前就执行,一般用来定义我们的内置变量(预定义变量,eg:FS,RS),可以输出表头(类似excel表格名称)
BEGIN模式,自定义变量,给内容变量赋值等,都是用过,需要注意的是BEGIN模式后面要接跟一夜action操作块,包含在大括号内。awk必须在对输入文件进行任何处理前限制性BEGIN里的动作(action)我们可以不要任何输入文件们就可以对BEGIN模块进行测试,因为awk需要限制性BEGIN模式,才对输入文件做处理。BEGIN模式常常被用来修改ORS,RS,FS,OFS等的值
2.6、取IP地址
[root@RedHat8-2 ~]# ifconfig ens32|awk -F "(inet )|( netmask)" 'NR==2{print $2}'
172.20.10.6
[root@RedHat8-2 ~]# ifconfig ens32|awk -F "[ :]+" 'NR==2{print $3}'
172.20.10.6
[root@RedHat8-2 ~]# ifconfig ens32|awk -F "[^0-9.]+" 'NR==2{print $2}'
172.20.10.6
也可以写成:
[root@RedHat8-2 ~]# ifconfig ens32|awk 'BEGIN{FS="(inet )|( netmask)"} NR==2{print $2}'
172.20.10.6
[root@RedHat8-2 ~]# ifconfig ens32|awk 'BEGIN{FS="[ :]+"} NR==2{print $3}'
172.20.10.6
[root@RedHat8-2 ~]# ifconfig ens32|awk 'BEGIN{FS="[^0-9.]+"} NR==2{print $2}'
172.20.10.6
注: 命令行-F本质就是修改的FS变量
2.6.1、第二个作用,在读取文件之前输出写提示性信息,表头
显示文件awkfile.txt的第一列和第三列(前期准备的测试文件 /etc/passwd前10行)并在第一行输出username和UID
[root@RedHat8-2 test]# awk -F: 'BEGIN{print "username","UID"} {print $1,$3}' awkfile.txt
username UID
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
2.6.2、第三种用法,使用BEGIN模块的特殊性质进行测试
简单输出内容
[root@RedHat8-2 ~]# awk 'BEGIN{print "Hello !"}'
Hello !
运行计算
[root@RedHat8-2 ~]# awk 'BEGIN{print 10/3}'
3.33333
[root@RedHat8-2 ~]# awk 'BEGIN{print 10/3+2}'
5.33333
[root@RedHat8-2 ~]# awk 'BEGIN{print 10/3+2/4*9}'
7.83333
和变量相关的操作
[root@RedHat8-2 ~]# awk 'BEGIN{a=1;b=2;print a,b}'
1 2
[root@RedHat8-2 ~]# awk 'BEGIN{a=1;b=2;print a,b,a-b}'
1 2 -1
2.6.3、第四种用法:配合getline读取文件
直接定义,直接使用即可
awk中字母会被认为是变量,如果真的要给一个变量赋值字母(字符串),使用双引号。
[root@RedHat8-2 ~]# awk 'BEGIN{a=1;print a}'
1
[root@RedHat8-2 ~]# awk 'BEGIN{a="xiaobai";print a}'
xiaobai
说明:
没有文件awk依旧可以处理BEGIN模式下的动作(命令)
2.6.4、END模式
END在awk读取完所有的文件的时候,在执行END模块,一般用来输出一个结果(累加,数组结果),也可以是和BEGIN模块类似的结尾标识信息。
[root@RedHat8-2 test]# awk 'BEGIN{print "name","ID"}{print $1$2,$3}END{print "Hello !" }' test.txt
name ID
zhaoyi 536489
qianer 125489
sunsan 894563
lisi 584965
zhouwu 224587
wuliu 336945
zhengqi 154785
wangba 987452
Hello !
2.6.5、统计/etc/services文件里面的空行数量
[root@RedHat8-2 test]# sed -n '/^$/p' /etc/services |wc -l
16
[root@RedHat8-2 test]# grep -n '^$' /etc/services |wc -l
16
[root@RedHat8-2 test]# grep -c '^$' /etc/services
16
[root@RedHat8-2 test]# awk '/^$/' /etc/services |wc -l
16
[root@RedHat8-2 test]# awk '/^$/{a++;print NR,a}' /etc/services
22 1
264 2
297 3
318 4
324 5
393 6
472 7
477 8
484 9
492 10
504 11
510 12
516 13
581 14
582 15
7844 16
[root@RedHat8-2 test]# awk '/^$/{i+=1}END{print i}' /etc/services
16
[root@RedHat8-2 test]# awk '/^$/{i=i+1}END{print i}' /etc/services
16
[root@RedHat8-2 test]# awk '/^$/{i++}END{print i}' /etc/services
16
[root@RedHat8-2 test]# awk '/^$/{a=a+1}END{print a}' /etc/services
16
[root@RedHat8-2 test]# awk '/^$/{c=c+1}END{print c}' /etc/services
16
#i++ == i=i+1
BEGIN awk中只能有一个
END awk中只能有一个
他俩可以同时出现。
第一步:统计空行个数
第二部:输出最后结果
[root@RedHat8-2 test]# awk '/^$/{i=i+1}END{print i}' /etc/services
16
awk编程思想:
1.先处理,最后在END模式输出。
2. {print NR,$0} body模块处理,处理完毕后
3. END{print "end of file"}输出一个结果
awk的调试技巧
让awk显示出每一步的执行结果
一般通过print来配合完成
几种常用的运算表达式
i=i+1 ==>i++
i=i+2 ==> i+=2
i=i+$0 ==> i+=$0
2.7、总结:
1、awk命令核心由模式和动作组成,就是‘找谁{干啥}’
2、模式就是条件,动作就是具体干什么
a、正则表达式:必须掌握正则
b、条件表达式:比大小,比较是否相等
c、范围表达式:从哪里来到哪里
3. 注意BEGIN或END模块只能有一个。BEGIN{}BEGIN{}或END{}END{}都是错误的
4、找谁干啥模块,可以是多个
a、'NR==2{print $1}NR==5{print $0}'
b、awk -F ":" 'NR==1{print NR,$0}NR==2{print NR,$NF}' awkfile.txt
内容为小白学习时的笔记,写出来供大家参考