基础知识梳理之awk命令

awk简介

一种怪异的语言

模式扫描和处理

awk不仅仅是linux中的一个命令,而且是一种编程语言,可以用来处理数据和生成报告。处理的数据可用是一个或多个,可以是来自标准输入,也可以通过管道获取标准输入,awk可以在命令行上直接编辑命令进行操作,也可以编写awk程序进行更为复杂的运用。

awk环境简介

[root@oldboy34 ~]# cat /etc/redhat-release

CentOS release 6.8 (Final)

[root@oldboy34 ~]# uname -r

2.6.32-642.el6.x86_64

[root@oldboy34 ~]# awk --version

GNU Awk 3.1.7 

awk格式

awk指令是由,模式,动作,或模式和动作的组合组成

模式即pattern,可以类似理解成sed的模式匹配,可以由表达式组成,也可以由表达式组成,也可以是两个正斜杠之间的正则表达式

动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。如awk使用格式:

awk [options] 'pattern{action}'

#     awk参数              模式动作

awk处理的内容可以来自标准输入(<)、一个或多个文本文件或管道

pattern即模式,也可以理解为条件

action即动作,可以理解为干啥

awk执行过程

案例文件的创建

mkdir /server/files/ -p

head /etc/passwd > /server/files/awkfile.txt

记录和字段

名称

含义

record

记录,行

field

域,区域,字段,列

awk对每个要处理的输入数据认为都是具有格式和结构的,而不仅仅是一堆字符串。默认情况下,每一行内容都是一条记录,并以换行符分割(\n)结束

awk记录分割符-RS

字段行

 

awk默认情况下每一行都是一个记录(record)

RS即record separator输入输入数据记录分割符,每一行是怎么没的,表示每个记录输入的时候的分割符,即行与行之间如何分割。

NR即number of record记录(行)号,表示当前正在处理的记录(行)的号码。

ORS即output record separator输出记录分隔符。

awk使用内置变量RS来存放输入记录分隔符,RS表示的是输入的记录分隔符这个值可以通过BEGIN模块重新定义修改。

示例:

[root@oldboy34 files]# head -2 awkfile.txt

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

[root@oldboy34 files]# 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

以:为没一行的结束

[root@oldboy34 files]# head -2 awkfile.txt

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

[root@oldboy34 files]# awk 'BEGIN{RS=":"}{print $1}' awkfile.txt

root

x

0

0

root

/root

/bin/bash

以连续的数字为每一行的结束

[root@oldboy34 files]# awk 'BEGIN{RS="[0-9]+"}{print NR,$0}' awkfile.txt

1 root:x:

2 :

3 :root:/root:/bin/bash

对$0的认识

awk使用$0来表示整条记录。记录分隔符存在RS变量中,或者说每一个记录以RS内置变量结束

awk对每行的记录号都有一个内置NR来保存,没处理完一条记录NR的值就会自动+1

说明

NR number of record,当前记录的记录号

$0 表示整行或者说整个记录

企业面试题:按单词出现频率降序排序(计算文件中每个单词的重复数)

注:(此处使用sort与uniq即可)

实验环境

[root@oldboy34 files]# sed -rn '1,10s#[^a-zA-Z]+# #gp' /etc/passwd >/server/files/count.txt

[root@oldboy34 files]# cat 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

uucp x uucp var spool uucp sbin nologin

解答

[root@oldboy34 files]# awk 'BEGIN{RS=" "}{print $0}' count.txt |sort |uniq -c

      1

      3 adm

      1 bash

      5 bin

      2 daemon

      3 halt

      2 lp

      1 lpd

      3 mail

      6 nologin

      3 root

     12 sbin

      3 shutdown

      3 spool

      3 sync

      3 uucp

      4 var

     10 x 

awk记录知识小结

NR(number of record)存放着每个记录的号(行号)读取新行时候会自动+1

RS(record separator)是输入数据的记录分隔符,简单理解就是指定每个记录的结尾标志

RS作用就是表示一个记录的结束

当我们修改了RS的值,最好配合NR(行)来查看变化,也就是修改了RS的值通过NR查看结果,调试awk

ORS输出数据的记录的分隔符

字段列

每条记录都是由多个区域(field)组成,默认情况下区域之间的分隔符是由空格(即空格或制表符)来分隔,并且将分隔符记录在内置变量FS中。每行记录的区域数据保存在awk的内置变量NF中。

field有很多钟解释,域、记录、区域。

FS即field separator,输入字段(列)分隔符,分隔符就是菜刀,把一行字符串切为很多个区域

NF即number of fileds,表示一行中列(字段)的个数,可以理解为菜刀切过一行后,切成了多少份。

OFS输出字段(列)分割符

awk使用内置变量FS来记录区域分隔符的内容,FS可以在命令行上通过-F参数来更改,也可以通过BEGIN模块来更改

然后通过$n,n是整数,来取被切割后的区域,$1取第一个区域,$2取第二个区域,$NF取最后一个区域。

ORS与OFS简介

RS是输入记录分隔符

ORS表示输出记录分隔符(output record separator),决定awk如何输出一行(记录)的,默认是回车换行(\n)。

FS是输入区域分隔符,决定awk读入一行后如何再分为多少区域

OFS表示输出区域分隔符,决定awk输出每个区域的时候使用什么分隔他们

[root@oldboy34 files]# cat 123.txt

aaa#bbb#ccc

aaa#bbb#ccc

aaa#bbb#ccc

aaa#bbb#ccc

aaa#bbb#ccc

aaa#bbb#ccc

aaa#bbb#ccc

aaa#bbb#ccc

aaa#bbb#ccc

aaa#bbb#ccc

aaa#bbb#ccc

[root@oldboy34 files]# awk 'BEGIN{FS="#";OFS="|"}{print $1,$2,$3}' 123.txt

aaa|bbb|ccc

aaa|bbb|ccc

aaa|bbb|ccc

aaa|bbb|ccc

aaa|bbb|ccc

aaa|bbb|ccc

aaa|bbb|ccc

aaa|bbb|ccc

aaa|bbb|ccc

aaa|bbb|ccc

aaa|bbb|ccc

字段记录小结

RS记录分隔符,表示每行的结束标志

NR行号(记录号)

FS字段分隔符,每列的分隔标志或结束标志

NF就是每行有多少列,每个记录中字段的数量

$符号表示取某个列(字段)

awk进阶

awk模式与动作

awk [options] 'pattern{action}' file

#     awk参数              模式动作

awk的模式都有几种

正则表达式为模式

比较表达式为模式

范围模式

特殊模式BEGIN和END

awk正则表达式练习题

实验环境

[root@oldboy34 files]# cat reg.txt

Zhang Dandan    41117397   :250:100:175

Zhang Xiaoyu    390320151  :155:90:201

Meng  Feixue    80042789   :250:60:50

Wu    Waiwai    70271111   :250:80:75

Liu   Bingbing  41117483   :250:100:175

Wang  Xiaoai    3515064655 :50:95:135

Zi    Gege      1986787350 :250:168:200

Li    Youjiu    918391635  :175:75:300

Lao   Nanhai    918391635  :250:100:175

显示姓Zhang的人的第二次捐款金额及他的名字

[root@oldboy34 files]# awk -F "[ :]+" '$1~/^Zhang/{print $2,$5}' reg.txt

Dandan 100

Xiaoyu 90

显示Xiaoyu的名字和ID号码

[root@oldboy34 files]# awk '$2~/^Xiaoyu$/{print $2,$3}' reg.txt

Xiaoyu 390320151

显示所有以41开头的ID号码的人的全民和ID号码

[root@oldboy34 files]# awk '$3~/^41/{print $1,$2,$3}' reg.txt

Zhang Dandan 41117397

Liu Bingbing 41117483

显示所有一个D或X开头人的全名

[root@oldboy34 files]# awk '$2~/^[DX]/' reg.txt

Zhang Dandan    41117397   :250:100:175

Zhang Xiaoyu    390320151  :155:90:201

Wang  Xiaoai    3515064655 :50:95:135
[root@oldboy34 files]# awk '$2~/^(D|X)/' reg.txt

Zhang Dandan    41117397   :250:100:175

Zhang Xiaoyu    390320151  :155:90:201

Wang  Xiaoai    3515064655 :50:95:135

显示所有ID号码最后一位数字是1或5的人的全名

[root@oldboy34 files]# awk '$3~/[15]$/' reg.txt

Zhang Xiaoyu    390320151  :155:90:201

Wu    Waiwai    70271111   :250:80:75

Wang  Xiaoai    3515064655 :50:95:135

Li    Youjiu    918391635  :175:75:300

Lao   Nanhai    918391635  :250:100:175

显示Xiaoyu的捐款,每个值时都有以$开头,如$520$200$135

[root@oldboy34 files]# awk '$2~/Xiaoyu/{gsub(/:/,"$",$NF);print $NF}' reg.txt

$155$90$201

显示所有人的全名,即姓,名的格式显示,如Meng,Feixue

[root@oldboy34 files]# awk '{print $2,$1}' reg.txt

Dandan Zhang

Xiaoyu Zhang

Feixue Meng

Waiwai Wu

Bingbing Liu

Xiaoai Wang

Gege Zi

Youjiu Li

Nanhai Lao

比较表达式作为模式

运算符

含义

示例

<

小于

x>y

<=

小于或等于

x<=y

==

等于

x==y

!=

不等于

x!=y

>

大于或等于

x>=y

>

大于

x<y

以上的运算符是针对数字,下面两个运算符之前已有示例,针对字符串

~

与正则表达式匹配

x~/y/

!~

与正则表达式不匹配

x!~y

案例

[root@oldboy34 files]# awk -F "[ :]" '$5>100' reg.txt

Wu    Waiwai    70271111   :250:80:75

Zi    Gege      1986787350 :250:168:200

Li    Youjiu    918391635  :175:75:300

找出/etc/passwd中第五列是root的行

[root@oldboy34 files]# awk -F: '$5=="root"' /etc/passwd

root:x:0:0:root:/root:/bin/bash

范围模式

pattern1

,

pattern2

从哪里来

哪里去

条件1

条件2

案例1:

[root@oldboy34 files]# awk '/^root/,/^shut/' awkfile.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

awk 特殊模式-BEGIN模式与END模式

BEGIN模块

BEGIN模块在awk读取文件之前就执行,一般用来定义我们的内置变量(预定义变量,eg:FS,RS),可以输出表头

BEGIN模式之前我们有在示例中提到,自定义变量,给内容变量赋值等,都用过。需要注意的是BEGIN模式后面要紧跟一个action操作块,包含在大括号内。awk必须在对输入文件进行任何处理前先执行BEGIN里面的动作(action)。我们可以不要任何输入文件,就可以对BEGIN模块进行测试,因为awk需要先执行完BEGIN模式,才对文件做处理。BEGIN模式常常被用来修改内置变量ORS,RS,FS,OFS等值。

[root@oldboy34 files]# awk -F: 'BEGIN{print "username","UID"}{print $1,$3}'  /server/files/awkfile.txt

username UID

root 0

bin 1

daemon 2

adm 3

lp 4

sync 5

shutdown 6

halt 7

mail 8

uucp 10

 

[root@oldboy34 files]# awk 'BEGIN{print 10/3}'

3.33333

[root@oldboy34 files]# awk 'BEGIN{print 10/3+1}'

4.33333

[root@oldboy34 files]# awk 'BEGIN{print 10/3+1/4*9}'

5.58333

awk中的概念简介

直接定义,直接使用即可

awk中的字母会被认为是变量,如果真的要给一个变量赋值字母(字符串),请用双引号。

[root@oldboy34 files]# awk 'BEGIN{a="yanghao";print a}'

yanghao

[root@oldboy34 files]# awk 'BEGIN{a=1;print a}'

1

[root@oldboy34 files]# awk 'BEGIN{a=123456;print a}'

123456

说明

没有文件awk依旧可以处理BEGIN模式下的动作(命令)

END模式

END在awk读取完所有的文件的时候,再执行END模块,一般用来输出一个结果(累加,数组结果),也可以是和BEGIN模块类似的结尾标识信息

[root@oldboy34 files]# awk 'BEGIN{print "hello world"}{print NR,$0}END{print "end of file"}' count.txt

hello world

1 root x root root bin bash

2 bin x bin bin sbin nologin

3 daemon x daemon sbin sbin nologin

4 adm x adm var adm sbin nologin

5 lp x lp var spool lpd sbin nologin

6 sync x sync sbin bin sync

7 shutdown x shutdown sbin sbin shutdown

8 halt x halt sbin sbin halt

9 mail x mail var spool mail sbin nologin

10 uucp x uucp var spool uucp sbin nologin

end of file

与BEGIN模式相对应的END模式,格式一样,但是END模式仅在awk处理完所有输入行后才处理.

企业案例3:统计/etc/services文件里面的空行数量

[root@oldboy34 files]# grep -c "^$" /etc/services

16

[root@oldboy34 files]# awk '/^$/{i=i+1}END{print i}' /etc/services

16

awk编程思想

1、先处理,最后在END模式输出

2、{print NR,$0}body模块处理,处理完毕后

3、END{print "end of file"}输出一个结果

几种常用的运算表达式

i=i+1   ====>i++

i=i+2    ====>i+=2

i=i+$0   ====>i+=$0

awk数组

指定分隔符

单引号

创建awk数组

取结果

单引号

 

awk -F "/+"

{hotel[$2]++}

#类似i++

END{for (pol  in hotel) print pol,hotel[pol]}

,

ur1.txt

先处理后输出(END模块输出)

[root@oldboy34 files]# awk 'BEGIN{hotel[110]="xiaoyu";hotel[119]="tandao";hotel[121]="feixue";print hotel[110],hotel[119],hotel[121]}'

xiaoyu tandao feixue

统计每个域名出现的次数,对域名进行去重,并显示重复数量

测试环境

http://www.etiantian.org/index.html

http://www.etiantian.org/1.html

http://post.etiantian.org/index.html

http://mp3.etiantian.org/index.html

http://www.etiantian.org/3.html

http://post.etiantian.org/2.html

 

[root@oldboy34 files]# awk -F "[/.]+" '{hotel[$2]++}END{for(pol in hotel) print pol,hotel[pol]}' ur1.txt

www 3

mp3 1

post 2

 

posted @ 2018-06-08 14:24  杨灏  阅读(457)  评论(0)    收藏  举报