Awk基础命令介绍(企业实战之一)

一:Awk是什么?

1.首先我们用专业的术语描述一下awk是什么?
awk是一个报告生成器,它拥有强大的文本格式化的能力,这就是专业的说法。

2.通俗易懂的理解awk
你可能不理解所谓的报告生成器中的"报告"指的是什么,你可以把"报告"理解为"报表"或者"表格",简单的说我们可以通过awk命令,将一些文本内容整理输出成我们想要的样子,比如把一些文本整理输出成""的样子,然后再展示出来,刚才概念中提到的"文本格式化的能力",也就是这个意思,其实这样说可能还是不太容易理解,不用着急,当你看到后面的"示例"时,自然会明白awk所
擅长的"文本格式化"能力是什么。 

(一): awk作者介绍

awk是由Alfred Aho 、Peter Weinberger 和 Brian Kernighan这三个人创造的,awk由这个三个人的姓氏的首个字母组成。

awk早期是在unix上实现的,所以,我们现在在linux的所使用的awk其实是gawk,也就是GNU awk,简称为gawk,awk还有一个版本,New awk,简称为nawk,但是linux中最常用的还是gawk。

awk其实是一门编程语言,它支持条件判断、数组、循环等功能。所以,我们也可以把awk理解成一个脚本语言解释器。

awk借鉴了c语法,因此awk在许多地方还保留有c语言的痕迹,比如printf语句;for,if的语法结构等 

(二): Linux中的"四剑客"

awk sed grep 被称为Linux中的“三剑客”,在加上我们功能强大的find 俗称“四剑客”
awk 擅长文件格式化,对文件进行较复杂的格式处理 
sed 擅长匹配处理行替换等 
grep 擅长过滤、查找、或匹配文件
find 擅长查找文件等

 

二Awk基础

(一):awk典型语法 

awk '{ 

     BEGIN{stat1} 
     BEGIN{stat2} 

     pattern1{action1} 
     pattern2{action2} 
     ... 
     patternn{actionn} 
     {默认动作,无条件,始终执行} 

     END{stat1} 
     END{stat2} 
}'

awk基本的语法

awk [options] 'Pattern{Action}' filename
command [选项 参数] '模式{动作}' 文件

从字面上理解 ,action指的就是动作,awk擅长文本格式化,并且将格式化以后的文本输出,所以awk最常用的动作就是print和printf,因为awk要把格式化完成后的文本输出啊,所以,这两个动作最常用(print和printf)。

我们先从最简单用法开始了解awk,我们先不使用[options] ,也不指定pattern,直接使用最简单的action,从而开始认识awk,如下

[root@egrep ~]# echo "hello world" >test
[root@egrep ~]# awk '{print}' test
hello world
[root@egrep ~]# awk '{print $1}' test
hello
[root@egrep ~]# awk '{print $0}' test
hello world

上面演示中,我们只是使用awk执行了一个打印的动作,将test文件中的内容打印了出来。

好了,现在,我们来操作一下另一个类似的场景。


[root@egrep ~]# df -h

第一列        第二列   第三列  第四列  第五列  第六列 

Filesystem   Size    Used   Avail  Use%   Mounted on
/dev/xvda1   40G     2.4G   35G    7%   /
devtmpfs     3.9G     0     3.9G   0%   /dev
tmpfs        3.9G     0     3.9G  0%   /dev/shm
tmpfs        3.9G    408K   3.9G  1%   /run
tmpfs        3.9G     0     3.9G  0%   /sys/fs/cgroup
tmpfs        783M     0     783M  0%   /run/user/0

[root@egrep ~]# df -h | awk '{print $5}'
Use%
7%
0%
0%
1%
0%
0%

上面演示中的示例没有使用到options和pattern,上图中的awk '{print $5}',表示输出df的信息的第5列,$5表示将当前行按照分隔符分割后的第5列,不指定分隔符时,默认使用空格作为分隔符,细心的你一定发现了,上述信息用的空格不止有一个,而是有连续多个空格,awk自动将连续的空格理解为一个分割符了,是不是比cut命令要简单很多,这样比较简单的例子,有利于我们开始了解awk。

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

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

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

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

[root@egrep ~]# df -h

第一列        第二列   第三列  第四列  第五列  第六列 

Filesystem   Size    Used   Avail  Use%   Mounted on
/dev/xvda1   40G     2.4G   35G    7%   /
devtmpfs     3.9G     0     3.9G   0%   /dev
tmpfs        3.9G     0     3.9G  0%   /dev/shm
tmpfs        3.9G    408K   3.9G  1%   /run
tmpfs        3.9G     0     3.9G  0%   /sys/fs/cgroup
tmpfs        783M     0     783M  0%   /run/user/0

[root@egrep ~]# df -h | awk '{print NF}'
7
6
6
6
6
6
6
[root@egrep ~]# df -h | awk '{print $NF}'
on
/
/dev
/dev/shm
/run
/sys/fs/cgroup
/run/user/0

通过以上的例子,我相信小伙伴们应该可以理解吧。

我们也可以一次输出多列,使用逗号隔开要输出的多个列,如下,一次性输出第一列和第二列

awk从放弃到入门(1):awk基础 (通俗易懂,快进来看)同理,也可以一次性输出多个指定的列,如下:

[root@egrep ~]# df -h | awk '{print $1,$2}'
Filesystem Size
/dev/xvda1 40G
devtmpfs 3.9G
tmpfs 3.9G
tmpfs 3.9G
tmpfs 3.9G
tmpfs 783M

[root@egrep ~]# awk '{print}' test
hello world awk
welcome to Linux world
[root@egrep ~]# awk '{print $1,$2}' test
hello world
welcome to
[root@egrep ~]# awk '{print $1,$3,$4}' test
hello awk
welcome Linux world

[root@egrep ~]# awk '{print $5}' test


[root@egrep ~]# awk '{print $5}' test | wc -l
2
[root@egrep ~]# awk '{print $5}' test | cat -n
1
2

awk从放弃到入门(1):awk基础 (通俗易懂,快进来看)我们发现,第一行并没有第5列,所以并没有输出任何文本,而第二行也没有第五列,所以也没有输出,显示多了两行空.这个证明了awk逐行处理.

除了输出文本中的列,我们还能够添加自己的字段,将自己的字段与文件中的列结合起来,如下做法,都是可以的。

[root@egrep ~]# awk '{print $1,$3,$4,"field5"}' test     
hello awk  field5
welcome Linux world field5
[root@egrep ~]# awk '{print $1,$3,$4,"field5","string6"}' test  
hello awk  field5 string6
welcome Linux world field5 string6

[root@egrep ~]# df -h | awk '{print "Disk: ",$0}'
Disk: Filesystem Size Used Avail Use% Mounted on
Disk: /dev/xvda1 40G 2.4G 35G 7% /
Disk: devtmpfs 3.9G 0 3.9G 0% /dev
Disk: tmpfs 3.9G 0 3.9G 0% /dev/shm
Disk: tmpfs 3.9G 440K 3.9G 1% /run
Disk: tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
Disk: tmpfs 783M 0 783M 0% /run/user/0

从上述实验中可以看出,awk可以灵活的将我们指定的字符与每一列进行拼接,或者把指定的字符当做一个新列插入到原来的列中,也就是awk格式化文本能力的体现。

但是要注意,$1这种内置变量的外侧不能加入双引号,否则$1会被当做文本字符串输出,示例如下

[root@egrep ~]# awk '{print}' test
hello world awk
welcome to Linux world
[root@egrep ~]# awk '{print $1}' test
hello
welcome
[root@egrep ~]# awk '{print "$1"}' test
$1
$1

#从上面看到如果我们给$1加上双引号,他就还是输出$1这里,可以简单的理解,通过在awk通过双引号都是字符串,字符串在双引号里面都是原封不动的。如果加了双引号,那么就会当做字符串处理.

我们也可以输出整行,如下有两种输出方式

[root@egrep ~]# awk '{print}' test
hello world awk 
welcome to Linux world   
[root@egrep ~]# awk '{print $0}' test
hello world awk 
welcome to Linux world   
#小编更喜欢第一种方式,简单快,第二种$0是内置变量,代表整行,

我们说过,awk的语法如下

awk [options] 'Pattern{Action}' file

而且我们说过awk是逐行处理的, 刚才已经说过了最常用的Action:print

现在,我们来认识下一Pattern,也就是我们所说的模式

不过,我们准备先把awk中最特殊的模式展示给大家,以后再介绍普通的模式,因为普通模式需要的篇幅比较长,所以我们先来总结特殊模式。

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

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

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

什么意思呢?光说不练不容易理解,我们来看一些小例子,先从BEGIN模式开始,示例如下

[root@egrep ~]# awk '{print}' test
hello world awk 
welcome to Linux world   
[root@egrep ~]# awk 'BEGIN{print "aaa","bbb"}' 
aaa bbb
[root@egrep ~]# awk 'BEGIN{print "aaa","bbb"}' test
aaa bbb

上述写法表示,在开始处理test文件中的文本之前,先执行打印动作,输出的内容为"aaa","bbb".

也就是说,上述示例中,虽然指定了test文件作为输入源,但是在开始处理test文本之前,需要先执行BEGIN模式指定的"打印"操作

既然还没有开始逐行处理test文件中的文本,那么是不是根本就不需要指定test文件呢,我们来试试。

[root@egrep ~]# awk 'BEGIN{print "aaa","bbb"}' 
aaa bbb

经过实验发现,还真是,我们并没有给定任何输入来源,awk就直接输出信息了,因为,BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的动作,而上述示例没有给定任何输入源,但是awk还是会先执行BEGIN模式指定的"打印"动作,打印完成后,发现并没有文本可以处理,于是就只完成了"打印 aaa bbb"的操作。

这个时候,如果我们想要awk先执行BEGIN模式指定的动作,再根据执我们自定义的动作去操作文本,该怎么办呢?示例如下

awk从放弃到入门(1):awk基础 (通俗易懂,快进来看)

[root@egrep ~]# awk '{print}' test
hello world awk 
welcome to Linux world   
[root@egrep ~]# awk 'BEGIN{print "aaa","bbb"}' 
aaa bbb
[root@egrep ~]# awk 'BEGIN{print "aaa","bbb"} {print $1,$2}' #这里记得接处理的文件,不然就卡住了
aaa bbb
^C 
[root@egrep ~]# awk 'BEGIN{print "aaa","bbb"} {print $1,$2}' test
aaa bbb
hello world
welcome to

上图中,红色标注的部分表示BEGIN模式指定的动作,这部分动作需要在处理指定的文本之前执行,所以,上图中先打印出了"aaa bbb",当BEGIN模式对应的动作完成后,在使用后面的动作处理对应的文本,即打印test文件中的第一列与第二列,这样解释应该比较清楚了吧。

看完上述示例,似乎更加容易理解BEGIN模式是什么意思了,BEGIN模式的作用就是,在开始逐行处理文本之前,先执行BEGIN模式所指定的动作。以此类推,END模式的作用就一目了然了,举例如下。

[root@egrep ~]# awk '{print $1,$2}END{print "ccc","ddd"}' test
hello world
welcome to
ccc ddd

聪明如你一定明白了,END模式就是在处理完所有的指定的文本之后,需要指定的动作。

那么,我们可以结合BEGIN模式和END模式一起使用。示例如下

[root@egrep ~]# awk '{print}' test
hello world awk 
welcome to Linux world 
[root@egrep ~]# awk 'BEGIN{print "AAA","BBB"}{print $1,$2}END{print "CCC","DDD"}' test      
AAA BBB
hello world
welcome to
CCC DDD

上述示例中返回的结果有没有很像一张"报表",有"表头"  、"表内容"、  "表尾",awk对文本的格式化能力你体会到了吗?

(二)内置变量

$0
当前记录(这个变量中存放着整个行的内容) 
$1~$n
当前记录的第n个字段,字段间由FS分隔 
FS
输入字段分隔符 默认是空格或\t
NF
当前记录中的字段个数,就是有多少列 
NR
已经读出的记录数,就是行号,从1开始,如果有多个文件话,这个值也是不断累加中。 
FNR
当前记录数,与NR不同的是,这个值会是各个文件自己的行号 
RS
输入的记录分隔符, 默认为换行符 
OFS
输出字段分隔符, 默认也是空格 
ORS
输出的记录分隔符,默认为换行符 
FILENAME
当前输入文件的名字

 

posted @ 2018-02-24 10:19  运维面试辅导  阅读(355)  评论(0)    收藏  举报