awk
基础理论
awk脚本是由模式和操作(动作)组成的
模式:
模式可以是以下任意一个:
1. /正则表达式/:使用通配符的扩展集。
2.关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试。
3. 模式匹配表达式:用运算符~(匹配)和~!(不匹配)。
4.BEGIN语句块、pattern语句块、END语句块:
动作:
1.变量或数组赋值
2.输出命令
3.内置函数
4.控制流语句
awk基本结构
一个awk脚本通常由:
1. BEGIN语句块。
2.能够使用模式匹配的通用语句块。
3. END语句块 3部分组成。
格式如下:
awk 'BEGIN{BEGIN部分的执行内容}{通用语句部分}END{结束后执行的内容}' 文件名
解释:
每一部分(除了BENGIN、END关键字外)都需要用{}扩起来。来区分这3个不同的部分。
例子:
awk 'BEGIN{print "---"}{print "china"}END{print "---"}' /etc/fstab
执行结果如下:
---
china
china
china
china
---
解释:
1、 BEGIN{print "---"}为第一部分,BENGIN标识了后边括号中的内容为begin部分
2、 {print "china"}为第二部分,通用语句块部分
3、 END{print "---"}为第三部分,END标识了后边大括号中的内容为END部分的内容
结束后要执行的语句块。
这三个部分是可选的。任意一个部分都可以不出现在脚本中,脚本通常是被单引号或双引号中.
例子1:
只出现BEGIN部分
[root@centos-1 ~]# awk 'BEGIN{print "---"}'
--
需要注意:
只出现BEGIN部分,后边不需要跟文件名
例子2
只出现通用语句块部分
[root@centos-1 ~]# awk '{print "china"}' /etc/fstab
china
china
china
china
china
china
需要注意:
只出现通用语句块部分,后边必须跟文件名。没有文件名不能正常处理
例子3:
只出现END语句块部分
[root@centos-1 ~]# awk 'END{print "---"}' /etc/fstab
---
需要注意:
只出现END语句块部分,后边必须跟文件名。没有文件名不能正常处理
awk工作流原理
第一步:执行BEGIN{}语句块中的语句;
第二步:从文件或标准输入(stdin)读取一行,然后执行{通用语句块}语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{}语句块。
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。
pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。
常看awk版本
[root@localhost pangbing]# awk -W version
GNU Awk 3.1.7
Copyright (C) 1989, 1991-2009 Free Software Foundation.
2.域和记录
域可以理解为”列”
在默认情况下,awk把文件按照空格分成不用的域(也就是列),
域的标记为$1 $2 $3.....。这种方法称为域标识。
$0表示所有域。例子:awk '{print $0}' 文件名
我们也可以通过-F选项来指定分割符,根据这个分割符把文件分成不同的域
例子:awk '{print $0}' 文件名 > 文件名 | tee 文件名
管道前边的结果会直接输出到文件,不会输出到屏幕上。tee命令就是能同时让结果输出到屏幕上。
打印不同的域,中间用逗号隔开。
例子:'{print$1,$3,$7}'
3.awk 匹配正则表达式
元字符:
这里是 a w k中正则表达式匹配操作中经常用到的字符:
\ ^ $ . [] [^] | () * +
?
条件操作符
表9 - 2给出a w k条件操作符,后面将给出其用法。
表9-2 awk条件操作符
操 作 符 描 述
操 作 符
描 述
<
小于
>=
大于等于
<=
小于等于
~ 匹配正则表达式
==
等于
!~ 不匹配正则表达式
!=
不等于
<1> 匹配
为使某一域号匹配正则表达式,使用符号‘~’后紧跟正则表达式
例子:
awk /root/ /etc/passwd 这个是简单的写法 ;passwd文件中只要含有root的行就打印出来
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
awk -F: '$1~/root/' /etc/passwd 意思是以:
为分隔符号,打印第一段(区域)匹配含有root的行
root:x:0:0:root:/root:/bin/bash
awk -F: '$3~/0/' /etc/passwd 意思是以:为分隔符号,打印第三段(区域)匹配含有0的行
awk -F: '$3=="0"' /etc/passwd 意思是以:为分隔符号,打印第三段(区域)匹配是0的行(这时精确匹配)
awk '/^ /' 文件名 匹配以空格开头的行
awk '/^ | ^#/' httpd.conf 匹配空格开头的或者是^#开头的
awk '!(/表达式1/&& /表达式2/)' /etc/passwd
表示取反
<2>. 精确匹配
为精确匹配 48,使用等号 ==,并用单引号括起条件。例如 $3==“48” ,这样确保只有 4 8序号得以匹配,其余则不行。
awk -F: '$3~/0/' /etc/passwd 意思是以:为分隔符号,打印第三段(区域)匹配含有0的行
root:x:0:0:root:/root:/bin/bash
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
pangbing:x:500:500:pangbing:/home/pangbing:/bin/bash
awk -F: '$3=="0"' /etc/passwd 意思是以:为分隔符号,打印第三段(区域)匹配只是0的行(这是精确匹配)
################
root:x:0:0:root:/root:/bin/bash
<3> 不匹配
awk -F: '$3!="0"' /etc/passwd
awk -F: '$3!~/0/' /etc/passwd
<4>比较
awk -F: '$3>=$4' /etc/passwd
4.计算
[root@localhost pangbing]# cat 1
1 11
2 12
3 14
4 22
<1>求和
格式: awk '{变量名+=第几列}END{print 变量名}' 文件名
[root@localhost pangbing]#
awk '{sum+=$1}END{print sum}' 1
10
[root@localhost pangbing]#
awk '{sum+=$2}END{print sum}' 1
59
<2>求平均值
格式:awk '{变量名+=第几列}END{print 变量名/NR}' 文件名
[root@localhost pangbing]# awk '{a+=$2}END{print a/NR}' 1
14.75
5.多条件同时匹配
[root@localhost pangbing]# cat 1
1 11
1 12 asd fff
1 13 2
同时匹配多个条件
格式:awk '条件1 && 条件2 && 条件...' 文件名
[root@localhost pangbing]#
awk '$1~/1/ && $2~/12/' 1
awk '$1~"1" && $2~"12"' 1 //也可以用""代替
1 12 asd fff
<1>前提是用 ~ 匹配时可以用双引号替换//,
<2>/表达式/单独出现时,不要用双引号替换,结果会有误。
时间段匹配
[root@centos-1 ~]# cat c
10:01
10:02
10:03
10:05
10:06
10:07
12:01
11:01
[root@centos-1 ~]# awk '$1>="10:05" && $1<="11:10"' c
10:05
10:06
10:07
11:01
awk的时间匹配是不受时间顺序的影响
[root@centos-1 ~]# awk '/10:05/,/11:10/' c
10:05
10:06
10:07
12:01
11:01
而这种匹配是受数值顺序的影响的,这里需要特别注意
6.awk中的for循环
[root@localhost pangbing]# cat b
pppppp
例子:[root@localhost pangbing]# awk '{for (i=1;i<=10;i++) print i}' b
1
2
3
4
其中
for(i=1;i<=10;i++)循环的意思是:定义了一个取值列表
for (变量=开始;停止循环的条件;步进长度)
停止循环的条件:是指满足条件就循环,不满足就停止循环。
误区:我这个循环理错了:
i做一次赋值运算,然后用i<=10这个条件判断i的值是不是小于10,然后做i的值做+1运算,然后i在从新赋值等于1,判断,运算。然后i在从新赋值等于1,判断,运算。我是这样错误理解这个循环的。这样i不是永远都 等于2了。
正确理解:这里边真正的循环体是i=1,
i<=10和i++:是给i=1循环时候添加的附加条件
i++:定义了 i 循环时候的运算方式。是说你每次循环都加1,
i<=10 :那么加到什么时候为止呢,i不在小于等于10的时候就停止循环。
循环过程:i=1 判断是否满足条件,满足就1+1
这时i=2了。还满足条件 在2+1
这时i=3了.还满足条件 在3+1
一直循环到不满足条件为止。
<2>另一种for的写法
这种写法和shell一样
for(i in 取值列表)
4. awk内置变量
a w k有许多内置变量用来设置环境信息。这些变量可以被改变。表 9 - 3显示了最常使用的
一些变量,并给出其基本含义
A R G C 命令行参数个数
A R G V 命令行参数排列
E N V I R O N 支持队列中系统环境变量的使用
FILENAME a w k浏览的文件名
F N R 浏览文件的记录数
F S 设置输入域分隔符,等价于命令行 - F选项
N F 浏览记录的域个数($NF表示最后一段。)
N R 已读的记录数
O F S 输出域分隔符
O R S 输出记录分隔符
R S 控制记录分隔符
5.ifconfig eth0 | awk -F[" ":]+ '/inet addr/ {print $4}'
这是快速过滤出IP地址的方法
echo 1234567890|awk -F "^C'{print $5}'
5
awk '{print $1,$NF,$(NF-1),$RS,$(NR-1),$(NR+1)}'
统计ip次数
awk '{print $1}' a.log |sort|uniq -c|sort -nr
优化后
awk '{a[$1]++}END{for (i in a)print a[i],i}'|sort -nr
*
a[$i]++
创建一个哈希数组,数组的key是每一列的内容a1、b1、a1、c1......,数组的value是每一列出现的次数
awk 哈希数组
awk printf 制表符
过滤ip地址
grep -o '\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}' urfile