前言
awk不仅仅是Linux系统中的一个命令,而且其还是一种编程语言,可以用来处理数据和生成报告(Excel)。处理的数据可以是一个或多个文件,它是Linux系统最强大的文本处理工具,没有之一。
【语法格式】
awk [option] ‘pattern{action}’ file …
awk [参数] ‘条件{动作}’ 文件 …
awk命令的常用功能
awk命令的参数选项及说明
案例1 :显示文件中的第5行
测试文件及内容如下:
#查看测试文件并每行编号 bash-5.0# cat -n reload.sh 1 echo "loading..." 2 # pid=`pidof skeleton.Master` 3 # kill -HUP $pid 4 pid=`ps -ef |grep skeleton.Worker| grep -v grep| awk '{print $1}'` 5 # | xargs kill -USR1 6 echo $pid 7 kill -9 $pid 8 # kill -USR1 $pid 9 echo "loading success"
bash-5.0# awk "NR==5" reload.sh # | xargs kill -USR1 #<==和上面内容对比确实是第5行
说明:
首先NR在awk中表示行号(记录号),NR==5表示行号等于5的行。这里需要注意的是必须使用两个等号,在awk中两个等号表示“等于”,一个等号表示赋值,即向一个变量里面放置内容。注意:awk后面所接的内容要用单引号。
命令拓展:显示一部分行的内容,例如显示2-5行。
bash-5.0# awk "NR==2,NR==5" reload.sh # pid=`pidof skeleton.Master` # kill -HUP $pid pid=`ps -ef |grep skeleton.Worker| grep -v grep| awk '{print $1}'` # | xargs kill -USR1
案例2:给文件每行的内容之前加上行号。
bash-5.0# awk '{print NR,$0}' reload.sh 1 echo "loading..." 2 # pid=`pidof skeleton.Master` 3 # kill -HUP $pid 4 pid=`ps -ef |grep skeleton.Worker| grep -v grep| awk '{print $1}'` 5 # | xargs kill -USR1 6 echo $pid 7 kill -9 $pid 8 # kill -USR1 $pid 9 echo "loading success"
说明:
这里的NR还是表示行号,$0表示一整行的内容(一行的内容)。print关键字表示显示的内容,相当于是awk内部的一个命令。那么print命令为何要放在花括号中呢?因为这个命令(动作)是“很害羞”的,需要“城墙”保护(花括号)。
案例3:显示文件的第2行到6行,并打印行号。
bash-5.0# awk 'NR==2,NR==5 {print NR,$0}' reload.sh #<==注意位置和写法。 2 # pid=`pidof skeleton.Master` 3 # kill -HUP $pid 4 pid=`ps -ef |grep skeleton.Worker| grep -v grep| awk '{print $1}'` 5 # | xargs kill -USR1
案例4:获取此文件的第1列和第三列、最后一列
bash-5.0# cat 1.txt qq:ww:ee:rr:ss:22:3333:221 zz:xxx:sss:ddd:aaa:f w:e:r:q:f:g:ghh:h:f:f:f:f qq:ww:ee:rr:ss:22:3333:221 w:e:r:q:f:g:ghh:h:f:f:f:f qq:ww:ee:rr:ss:22:3333:221 zz:xxx:sss:ddd:aaa:f qq:ww:ee:rr:ss:22:3333:221
bash-5.0# awk -F ':' '{print $1,$3,$NF}' 1.txt qq ee 221 zz sss f w r f qq ee 221 w r f qq ee 221 zz sss f qq ee 221
说明:
这里我们使用了awk的-F参数,注意一定要是大写的,-F参数表示指定分隔符来切割每一行的内容,-F后面可用单双引号或不加引号,但是,建议加双引号。
这里我们指定的分隔符是冒号“:”,这样该行就被不同的冒号切割成了很多个部分。
切成了很多个部分之后,若我们要使用某一个部分该怎么办?使用“$(美元符号)”后面接数字,$1表示第一个部分(第一列),$2(第二列),$3(第三列),依此类推,但$0表示整行。
这里有一个特殊的表示最后一列的方法,就通过$NF来表示最后一列。
案例5:使用awk将文件中的qq替换为tihuan(使用awk函数实现)
bash-5.0# awk '{gsub("qq","tihuan",$0);print $0}' 1.txt tihuan:ww:ee:rr:ss:22:3333:221 zz:xxx:sss:ddd:aaa:f w:e:r:q:f:g:ghh:h:f:f:f:f tihuan:ww:ee:rr:ss:22:3333:221 w:e:r:q:f:g:ghh:h:f:f:f:f tihuan:ww:ee:rr:ss:22:3333:221 zz:xxx:sss:ddd:aaa:f tihuan:ww:ee:rr:ss:22:3333:221
这里使用的是awk里面的查找替换功能,即gsub函数。
gsub的格式如下:
gsub(“替换对象”,“替换成什么内容”,哪一列)
注意:
- gsub与后面的括号之间不能有空格。
- 替换对象、替换成什么内容以及哪一列之间要用逗号分隔开。
- 替换对象的外面要有双引号或双斜线包裹起来,即“替换对象”或/替换对象/。
- 替换成什么内容就只能用双引号包裹起来了,即“替换成什么内容”。
- 最后一个是哪一列,这个是可以省略的,省略的时候表示要替换整行的内容,相当于是写上了$0。
案例6:取出eth0网卡对应的ip地址。
本地机器的ip信息如下
bash-5.0# ifconfig eth0 eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:26 errors:0 dropped:0 overruns:0 frame:0 TX packets:5 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1968 (1.9 KiB) TX bytes:246 (246.0 B)
本例的方法特别多,这里仅使用awk给出常见的实现。
方法1
bash-5.0# ifconfig eth0 |awk -F "(addr:)|( Bcast:)" 'NR==2{print $2}' 172.17.0.2
说明:
-F"(addr:)|(Bcast:)"这个还是比较容易理解的,我们的目标是取得ip,本例是10.0.0.8,ip的左边是“addr:”,右边是“Bcast:”,左边分隔,即把“addr:”作为分隔符,右边分隔,即把“Bcast:”作为分隔符,剩下中间的ip就是我们想要的。
但是还需要一个条件,ip地址在第二行所以使用NR==2来表示。
方法2
bash-5.0# ifconfig eth0|awk -F "[ :]+" 'NR==2{print $4}' 172.17.0.2
说明:
172.17.0.2的左边挨着的是冒号,因此可以用冒号作为分隔符,即-F":“。
172.17.0.2的右边挨着的是空格,因此可以用空格作为分隔符,即-F”“。
但是行的最左边是多个空格又该怎么处理呢?
很简单,可以用正则表达式的加号(+),表示重复前面一个字符一次或一次以上。
结合起来就是,-F”[:]+"以单个或连续的空格或冒号或者它们的组合为分隔符,最后就可以获得我们想要的ip地址。
案例7:将域名取出并根据域名进行计数排序处理(百度和搜狐面试题):
bash-5.0# cat domainTest.txt 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
1.取出域名
bash-5.0# awk -F '/' '{print $3}' domainTest.txt www.etiantian.org www.etiantian.org post.etiantian.org mp3.etiantian.org www.etiantian.org post.etiantian.org
2.排序
bash-5.0# awk -F '/' '{print $3}' domainTest.txt | sort mp3.etiantian.org post.etiantian.org post.etiantian.org www.etiantian.org www.etiantian.org www.etiantian.org
3.去重计数
awk -F '/' '{print $3}' domainTest.txt | sort | uniq -c 1 mp3.etiantian.org 2 post.etiantian.org 3 www.etiantian.org