【转载】[一文一命令]awk命令详解

来源:互联网 发布:什么是js面向对象编程 编辑:程序博客网 时间:2024/06/08 15:09
作者: woshiliwentong
时间: 2013-12-21 17:59:09
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://atong.blog.51cto.com/2393905/1343553

awk

简介:

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

awk3个不同版本: awknawkgawk,未作特别说明,一般指gawkgawk AWK  GNU 版本。awk其名称得自于它的创始人 Alfred Aho Peter Weinberger  Brian Kernighan 姓氏的首个字母。实际上 AWK 的确拥有自己的语言: AWK 程序设计语言三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。


功能描述:

awk -F ‘分隔符’ '条件类型1{动作1} 条件类型2{动作2} ...' filename

尽管操作可能会很复杂,但语法总是这样,其中条件类型表示 AWK 在数据中查找的内容,而动作是在找到匹配内容时所执行的一系列命令。大括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。 条件类型就是要表示的正则表达式,用斜杠括起来。通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。

Awk的某一个动作中可以有多条处理指令,每条指令用;分隔。并且能够加上判断语句,循环语句、数组等。具体的使用将在后续的内容中体现。Awk可以有选择的,指定的小范围内的对数据进行处理。

-------------------------------自己对以上理论知识的理解-------------------------------

[PS:那么也就是说awk比grep选择内容命令、sed选择&编辑命令更加强大,同样也是对一整行来进行处理。不仅能够根据我们设定的条件来进行内容的选定,还能够对我们选择出来的内容进行处理。处理的时候,还能够加入判断、循环、数组(这几个都是十分强劲而且有用的)。简直了都,岂不是用awk就能够完成很多,内容选择,编辑什么的功能了。那用这一个就好了。其实如果简单的功能还是使用简单的命令比较好啦。因为够直接嘛。]

   哈哈,以上的理解肯定有偏差的,不过我自己的理解而已嘛,大家可以忽略的。

----------------------------------------------------------------------------------------



调用awk的方式:

有三种方式调用awk

1.命令行方式

awk [-F  field-separator(字段分隔符)]'commands'input-file(s)其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。

2.shell脚本方式

将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。相当于shell脚本首行的:#!/bin/sh。可以换成:#!/bin/awk

3.将所有的awk命令插入一个单独文件,然后调用:

awk -fawk-script-file input-file(s)其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。


awk内置变量:

awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。

ARGC               命令行参数个数

ARGV               命令行参数排列

ENVIRON            支持队列中系统环境变量的使用

FILENAME           awk浏览的文件名

FNR浏览文件的记录数

FS                 设置输入域分隔符,等价于命令行-F选项

NF(number field)  浏览记录的域的个数:也就是根据分隔符来算第几个字段。

NR(number read)已读的记录数

OFS                输出域分隔符

ORS                输出记录分隔符

RS                 控制记录分隔符

注意:$0变量是指整条记录$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。


使用实例

Awk简单指令操作

(1)只显示最后登录系统的5个用户名

[root@LiWenTong ~]# last -5

root    pts/0        192.168.40.22    Wed May 1 08:31   still logged in  

reboot  system boot  2.6.18-238.el5   Wed May 1 08:28          (08:55)    

root    pts/0        192.168.1.105    Tue Apr 30 20:41 - down   (01:40)  

root    tty1                          TueApr 30 20:40 - down   (01:42)    

[root@LiWenTong ~]# last -5 | awk '{print $1}' --->最简单的对输出信息,进行提取。

root

reboot

root

root

注:awk工作流程是这样的:读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域。默认域分隔符是"空白键 "[tab]",所以$1表示登录用户,$3表示登录用户ip,以此类推。


(2)指定分隔符的提取

[root@LiWenTong ~]# cat -n /etc/passwd | awk -F ':' '{print $1}'|sed -n '1,10p'--->awk指定分隔符为:并且取出第一栏内容出来而已。

-----插播-------------------------------------------------------------

awk [-F  field-separator(字段分隔符)] 'commands'input-file(s)---》这个是我们刚才说的awk的命令格式。以上实例的命令的-F就是对应的,很好认。‘{print $1}’也就命令格式的‘commands’部分。

-----------------------------------------------------------------------

    1  root

    2  bin

    3  daemon

    4  adm

    5  lp

    6  sync

    7  shutdown

    8  halt

    9  mail

10  news

[root@LiWenTong ~]# cat -n /etc/passwd | awk -F ':' '{print$1"\t"$7}'|sed -n '1,10p'

    1  root   /bin/bash

    2  bin    /sbin/nologin

    3  daemon /sbin/nologin

    4  adm    /sbin/nologin

    5  lp     /sbin/nologin

    6  sync   /bin/sync

    7  shutdown        /sbin/shutdown

    8  halt   /sbin/halt

    9  mail   /sbin/nologin


(3)如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"

[root@LiWenTong ~]# cat /etc/passwd | awk -F ':' 'BEGIN{print"number,user,shell"} {print NR"\t"$1"\t"$7}'|sed -n '1,10p' ---->遗漏了END{print”blue,/bin/nosh”}内容。

----插播--------------------------

在'commands'里面可以加上命令执行的时间点:

'BEGIN{开始的时候执行}  {每行执行的部分}  END{行都读完后执行}'

----------------------------------

number,user,shell

1      root    /bin/bash

2      bin     /sbin/nologin

3      daemon  /sbin/nologin

4      adm     /sbin/nologin

5      lp      /sbin/nologin

6      sync    /bin/sync

7      shutdown        /sbin/shutdown

8      halt    /sbin/halt

9      mail    /sbin/nologin

注:awk工作流程是这样的:先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。NR:表示当前已经读取到第几行内容。


(4)搜索/etc/passwdroot关键字的所有行

[root@LiWenTong ~]# awk -F':' '/root/'/etc/passwd—》当没有指定action的时候,默认就只是对匹配条件的语句进行输出而已。后面接上具体的file进行匹配搜索。条件语句也可以结合正则表达式。

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

operator:x:11:0:operator:/root:/sbin/nologin

[root@LiWenTong ~]# awk  '/mjfan/{print$1} ' 1.log---->这个就有综合了内容选择和内容编辑的命令了

hrwang

mjfan

mjfan

Awk编程

(1)统计/etc/passwd里面的用户数。

[root@LiWenTong ~]# awk -F ':' '{count=0;count++}{printNR"\t"$1}END{print"user count is:",count }' /etc/passwd--->第一次给变量count赋值,并自增。但结果显示却是count:1,后回想起awk是逐条进行处理,那么每处理新的一条count又被重新赋值了,应该是第一次赋值其余不用再赋值应该加上BEGIN.

1       root

2       bin

3      daemon

4       adm

5       lp

6       sync

7      shutdown

32     avahi-autoipd

33      test

Usercount is: 1--->看到执行出错了

[root@LiWenTong ~]# awk -F ':' 'BEGIN{count=0}{count++}{printNR"\t"$1}END{print"user count is:",count }' /etc/passwd--->修改后加上BEGIN 之后就正确了,awk确实好用,能够嵌套多条指令!!---->其实这个应该可以吧count++放在print NR这个{}里面然后用;分割开来。

1       root

2       bin

3      daemon

4       adm

5       lp

6       sync

7      shutdown

31     haldaemon

32     avahi-autoipd

33      test

Usercount is: 33----看到这次执行正确了


(2)统计某个文件夹下的文件的字节数

[root@LiWenTong ~]# ls  -l | awk'BEGIN{size=0}{size=size+$5;print NR"\t"$5}END{print"All sizeis:",size}'---------->只是比较奇怪的是,为什么会多出一个第一条,而且是没有记录的?哦,在写博客的时候我突然就明白了,这个就是. 所以没有显示大小。还有记住了中间的这个{}里面的每读入一行都会执行一次的哦。卡卡,我反复的强调也让自己记住啦。反正这个是要记住的,刚开始学这个命令比较容易忽略这个东西,想不透彻。

1

2       218

3       24

4       31

5       0

6       0

7       960

8       3692

All size is: 2995


‘commands’中的Action:可以是循环、判断语句,还有数组呢!这些很强劲的。

1统计某个文件夹下的文件占用的字节数,过滤4096大小的文件(一般都是文件夹)

[root@LiWenTong ~]# ls  -l | awk 'BEGIN{size=0}{if($5!=4096){size=size+$5;printNR"\t"$5}}END{print"All size is:",size}'---》在action中加入if判断语句进行判断,如果文件大小为4096的忽略不计。(4096一般是文件夹的大小)

1

2       218

3       24

4       31

5       0

6       0

7       960

All size is: 25863

说明:awk中的循环语句同样支持whiledo/whileforbreakcontinueawk命令真的是超级强劲的。

awkcommand丰富,处理能力超强》

Awk 后能够接的命令有很多,在搜索的时候也能够接上正则表达,那么能够达成的搜索结果就更加厉害。

-----------------------------后续自我小结------------------------

   在awk的介绍中有说awk其实是一门程序呢,所以说它的功能真的很强。哎呀就不再说这个了。awk的基本命令格式是awk -F '分隔符' ‘commands’ 待处理的file    commands 里面的格式可以是这样的:条件选择命令{执行的动作命令};条件2{动作2}。条件也可以是指定时间点入 BEGIN{动作} {动作} END{动作}这样的方式。

   并且如果再细分动作的:就更加丰富了,不能是简单内容操作命令(也就是一些编辑命令等。如print $1、echo $0 > 1.txt、grep $1 1.txt > 2.txt  其实就是一些我们系统中能够正常执行的语句都可以用在这里的。哈哈,其实我也是写博文的时候才这样觉得的,还没来得及去验证一下。不过这样想法应该是没错了)。还能够加上一些判断、选择、数组等呢,这样功能实现上就更强了。

   恩我对了我常说数组,其实我对数组还不是很熟悉的啦。要不我们马山来了解一下好了。就接在这后面,继续写吧。本来要小结结束的。

-------------------------------------------------------------------

来自此博文:http://oldboy.blog.51cto.com/2561410/1184177

4.1统计apache日志单ip访问请求数排名(这个常用,考试也常考)

假设apache日志内容access.log内容为:

10.0.0.41 - - [03/Dec/2010:23:27:01 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

10.0.0.43 - - [03/Dec/2010:23:27:01 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

10.0.0.42 - - [03/Dec/2010:23:27:01 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

10.0.0.46 - - [03/Dec/2010:23:27:02 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

10.0.0.42 - - [03/Dec/2010:23:27:02 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

10.0.0.47 - - [03/Dec/2010:23:27:02 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

10.0.0.41 - - [03/Dec/2010:23:27:02 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

10.0.0.47 - - [03/Dec/2010:23:27:02 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

10.0.0.41 - - [03/Dec/2010:23:27:03 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

10.0.0.46 - - [03/Dec/2010:23:27:03 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

   恩,我只看了题目而已,我先来试一下吧。我们肯定是要获取$1 然后统计每个$1的个数。最后再输出来$1  还有每个$1的个数,这两个数值就可以了。$1就是访问的ip呀。恩,大概是这样的一个结构吧{SZ[$1];SZ[$1]++},然后怎么输出呢?恩,数组有数组名、还有数组名对应的数值,$1就是数组名统计的个数就是数组名对应的数值。对了,那只要把数组名、和数组名对应的数值输出就可以了。输出数组名?这个好像比较难,我知道SZ就是数组中所有数组名的集合,之要把SZ一个一个输出就可以了。用循环输出?好吧,查看下别人是怎么做的吧。果真是用for,for( a in SZ)print a ,SZ[a]来输出数组名和数值。恩,那完整的应该是这样的。

   #cat access.log| awk  'BEGIN{printf"必要的说明" {SZ[$1];SZ[$1]++} END{for(a in SZ)print a,SZ[a]} }'   恩这样应该就没有错了吧,卡卡。

好啦,确实是这样的,恩以前看过知道有这么回事,这回自己思考确实印象比较深刻了。数组名需要用循环来输出的。

   另:以上的老男孩的博文中还加入了排序命令,这样方便统计恩。那我们的数组就先到这边吧。

-------------------------------后续自我小结-----------------

awk数组的使用确实很好用,能够在实际的运维工作中起到一个很好的作用。重点就是在于理解数组是怎样的结构,数组名要对应什么,数组名的数值就是我们要统计的数值了。然后要怎么输出者个数组名,用for (a in SZ) print a,SZ[a] 这样来让数组名和数组的值输出出来。咔咔,其实认真的理解一下应该也是不难的嘛。

以后只要我们需要对某个特别列,并且列中总有不同的项目进行数值的统计,我们就可以使用awk的数组功能咯。是不是真的很强大呀。

-------------------------------------------------------------

再加上几个老男孩有关awk的博文:

http://oldboy.blog.51cto.com/2561410/950730

http://oldboy.blog.51cto.com/2561410/1184165

http://oldboy.blog.51cto.com/2561410/1184177


本文出自 “从头开始” 博客,请务必保留此出处http://atong.blog.51cto.com/2393905/1343553

2013-12-21 17:59:09
原创粉丝点击