【转】awk 详解
转自:http://blog.sina.com.cn/s/blog_a05fe43b0101qt09.html
一. AWK 说明
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。
awk处理文本和数据的方式:它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。
awk是一门语言:作用是做报表,日志分析等等。读取的时候是一次一行读取文件的。
二. awk命令格式和选项
2.1. awk的语法有两种形式
awk [options] 'command' filename
awk [options] -f scriptfile var=value filename
2.2. 命令选项
(1)-F fs or --field-separator fs :指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。
(2)-v var=value 从shell脚本传递变量到awk脚本或者命令中
(3)-f scripfile or --file scriptfile :从脚本文件中读取awk命令
三、变量
3.1.内置变量
内置变量 描述
$n 当前记录的第n个字段,字段间由FS分隔。★
$0 完整的输入记录。★
FS 字段分隔符(默认是任何空格)。★
NF 当前记录中的字段数。★
NR 当前记录数。★
OFS 输出字段分隔符(默认值是一个空格)。★
ARGC 命令行参数的数目。
ARGIND 命令行中当前文件的位置(从0开始算)。
ARGV 包含命令行参数的数组。
CONVFMT 数字转换格式(默认值为%.6g)
ENVIRON 环境变量关联数组。
ERRNO 最后一个系统错误的描述。
FIELDWIDTHS 字段宽度列表(用空格键分隔)。
FILENAME 当前文件名。
FNR 同NR,但相对于当前文件。
IGNORECASE 如果为真,则进行忽略大小写的匹配。
OFMT 数字的输出格式(默认值是%.6g)。
ORS 输出记录分隔符(默认值是一个换行符)。
RLENGTH 由match函数所匹配的字符串的长度。
RS 记录分隔符(默认是一个换行符)。
RSTART 由match函数所匹配的字符串的第一个位置。
SUBSEP 数组下标分隔符(默认值是\034)。
3.2.用户自定义变量
在awk中变量无须定义即可使用,变量在赋值时即已经完成了定义。变量的类型可以是数字、字符串。
根据使用的不同,未初始化变量的值为0或空白字符串" ",这主要取决于变量应用的上下文。
例子一、
awk '$1 ~ /lg/ {mem = $2 * $3; print mem}' filename
例子二、
awk '$1 ~ /huang/ {name=$1; print name}' filename
3.3. 数组
awk数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。
值和关键字都存储在内部的一张针对key/value应用hash的表格里。
数组初始化(定义):
arr[1]=1
arr[2]=5
str_arr["a"]="test"
str_arr["b"]="test1"
例如一、
awk 'BEGIN{str_tmp="it is a test";split(str_tmp,str_arr," ");for(k in str_arr){print k,str_arr[k];}}'
#split是awk一个内置函数split(str_tmp,str_arr," ")操作之后会把 str_tmp变量按照空格分隔存储在数组str_arr中
#注意:splite截取的数组下标从1开始。
四、运算符
运算符 描述
= += -= *= /= %= ^= ** 赋值
?: C条件表达式
|| 逻辑或
&& 逻辑与
~ 匹配正则表达式
!~ 匹配正则表达式
< <= > >= != == 关系运算符
空格 连接
+ - 加,减
* / & 乘,除与求余
+ - ! 一元加,减和逻辑非
^ *** 求幂
++ -- 增加或减少,作为前缀或后缀
$ 字段引用
例子:
例一、匹配操作符(~)
awk '$1 ~/^root/' test将显示test文件第一列中以root开头的行。 awk '$1 !~/^root/' test将显示test文件第一列中不以root开头的行。
例二、比较表达式
awk 'BEGIN{num= 2>3? 2:3;print num}' #练习?:符合比较大小同时赋值 awk '$1 + $2 < 100' test。如果第一和第二个域相加大于100,则打印这些行。
五. 记录和域
1. 记录
awk把每一个以换行符结束的行称为一个记录。
$0变量:它指的是整条记录。
变量NR:一个计数器,每处理完一条记录,NR的值就增加1。
例如:
awk '{print NR,$0}' test.txt #将输出test.txt文件中所有行号和内容
2. 域分隔符
- 输入分隔符:当文件记录输入一行时候,默认是空格或tab为分隔,把这行分隔成一列一列。
- 那么tab和空格就是分隔符,内建变量FS保存输入域分隔符的值。
- 可以通过-F选项自定义修改FS的值。
- 可以同时使用多个域分隔符,这时应该把分隔符写成放到方括号中。
- 输出分隔符:输出域的分隔符默认是一个空格,保存在OFS内建变量中。
例子:
awk -F: '{print $2,$4}' test.txt #将打印以冒号为分隔符的第二,第四列的内容。 awk -F'[:\t]' '{print $1,$3}' test.txt,表示以空格、冒号和tab作为分隔符。 awk -F: '{print $1,$5}' test.txt #$1和$5间的逗号就是OFS的值。 awk 'BEGIN { OFS="%"} {print $1,$2}' test.txt 通过设置输出分隔符(OFS="%")修改输出格式。
3. 域
记录中每个以分隔符分隔的间隔中的内容称做“域”,默认情况下以空格或tab分隔。
awk可跟踪域的个数,并在内建变量NF中保存该值。
例子:
awk '{print $3,$5}' test.txt #将打印test.txt文件中第三和第五个以空格分开的列(域)。
六、内置函数
内置函数主要是处理字符串(文本)函数:
delete arr[1] | 删除数组中的下标为1的元素. |
length(string) | 字符串长度。 |
index(string1,"abc") | 查询字符串string1中"abc"是第几个。从一开始数。 |
tolower(mystring) | 字符串转换为小写 |
toupper(mystring) | 字符串转换为大写 |
substr(mystring,start,length) | #截取字符串mystring中从start开始,length长度。 |
match(mystring,/[0-9]/) |
#正则匹配字符串,其中匹配完后结果会存储在内置变量RSTART #说明:/root/匹配的正则。RSTART 包含返回值(第一个匹配的位置) |
替换:
sub(regex,regexstring,mystring)是把mystring中的包含regex的字符串替换为regexstring
切分:
split(mystring,存储,以什么分割)
nums=split("a,b,c,sdfd,se",myeles,","); #nums是数组中元素个数。
例子:
1.match练习
[lg@master ~]$ awk '{match($0,/Tom/);print RLENGTH,RSTART}' test.txt 3 9 -1 0 -1 0 [lg@master ~]$ cat test.txt To 1000 Tom 89 Tom lg 2000 lg 2000 te
2.tolower和toupper
awk '{str=tolower($0);print str}' test.txt awk '{str=toupper($0);print str}' test.txt
3.length(string)
awk '{len=length($0);print len}' test.txt
4.index(string1,"abc")
awk '{num=index($0,"Tom");print num}' test.txt
5.substr(mystring,start,length);
awk '{str=substr($0,1,2);print str}' test.txt
七、awk中调用shell命令
1. 使用system函数system("cmd")
awk 'BEGIN{ while( system("ls -l") | getline line ){ print line } }'
2."cmd"调用
awk 'BEGIN{ "date +%Y%m%d-%H" | getline date; print date; }' awk 'BEGIN{ while(("ls"|getline line)>0) print line; }'
3.交互是输入
awk 'BEGIN{ getline; print $0 }'
八、编程脚本
编程脚本分三部分。BEGIN区 正文区 END区(三个部分可以有可以没有)
完整写法:
BEGIN{
}
{
}
END{
}
说明:BEGIN 和END都执行一次,BEGIN是开始时候执行一次,END是结束读取时候执行那个一次。
正文区是一直读取,执行。
使用文件:-f
举例子
myawk.awk
BEGIN{
print "start...."
FS=":"
}
{
print "username:" $1 "uid:" $3
}
END{
print "end...."
}
使用时候:
awk -f myawk.awk /etc/passwd
九、编程语句
1. if条件语句(说明其中的if就和c语言一样,不用之间有空格)
if($2~/root/) {
print $1
} else if($3=="adf"){
print "sdf"
} else {
print $4
}
awk '!/root/ {print}' filename是不含root的使用脚本如下:
if($0!~/root/) {
print $2
}
2. for循环语句:
for(i=0;i<4; i++) {
print i
}
3. while循环语句:
while($1=="sdf"){
i++
}
do{
i++
}while(i<4)
4.控制语句:
exit(1) 整个程序退出。
break 整个循环语句退出
continue 跳过continue以下的语句,循环直接换回上边继续循环。
十、实战例子
1.查看系统ip地址,只需要ip地址
ifconfig|egrep "inet addr"|awk '{print $2}'|awk -F ":" '{print $2}'
2、统计apache日志单ip连接数排名(这个常用,考试也常考)
练习日志:
10.0.0.41 - - [03/Dec/2010:23:27:01 +0800] "HEAD /ch.jsp HTTP/1.0" 200 - 10.0.0.43 - - [03/Dec/2010:23:27:01 +0800] "HEAD /cg.jsp HTTP/1.0" 200 - 10.0.0.42 - - [03/Dec/2010:23:27:01 +0800] "HEAD /test.jsp HTTP/1.0" 200 - 10.0.0.46 - - [03/Dec/2010:23:27:02 +0800] "HEAD /s.jsp HTTP/1.0" 200 - 10.0.0.42 - - [03/Dec/2010:23:27:02 +0800] "HEAD /a.do HTTP/1.0" 200 - 10.0.0.47 - - [03/Dec/2010:23:27:02 +0800] "HEAD /b.html HTTP/1.0" 200 - 10.0.0.47 - - [03/Dec/2010:23:27:02 +0800] "HEAD /csj.jsp HTTP/1.0" 200 - 10.0.0.47 - - [03/Dec/2010:23:27:02 +0800] "HEAD /jsa.jsp HTTP/1.0" 200 - 10.0.0.41 - - [03/Dec/2010:23:27:03 +0800] "HEAD /do.jsp HTTP/1.0" 200 - 10.0.0.46 - - [03/Dec/2010:23:27:03 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200
答案:
方法一:
awk '{print $1}' apache.log|sort |uniq -c |sort -rn|head -10
方法二:
awk '{++S[$1]} END {for(a in S) print a,S[a]}' apache.log |sort -k2
3.统计访问请求中同一时间tcp状态排名.
netstat -an 截取的一段 内容:
tcp 0 0 202.34.35.123:80 222.221.145.251:2002 TIME_WAIT tcp 0 0 202.34.35.123:80 121.207.188.230:1739 ESTABLISHED tcp 0 0 202.34.35.123:80 210.38.1.84:4183 SYN_RECV tcp 0 0 202.34.35.123:80 113.89.34.7:46474 ESTABLISHED tcp 0 0 202.34.35.123:80 221.213.1.42:58778 LAST_ACK tcp 0 0 202.34.35.123:80 203.208.60.195:54066 TIME_WAIT tcp 0 0 202.34.35.123:80 60.12.201.67:8268 ESTABLISHED tcp 0 0 202.34.35.123:80 113.125.75.149:58155 SYN_RECV tcp 0 0 202.34.35.123:80 114.239.53.232:1198 SYN_RECV tcp 0 0 202.34.35.123:80 59.37.230.66:2439 ESTABLISHED tcp 0 0 202.34.35.123:80 110.18.8.117:2882 SYN_RECV tcp 0 0 202.34.35.123:80 113.125.75.149:58161 ESTABLISHED tcp 0 0 202.34.35.123:80 123.165.3.37:9698 SYN_RECV tcp 0 0 202.34.35.123:80 113.125.75.149:58157 SYN_RECV
解答:
方法二:
netstat -an|grep "^tcp"|awk '{print $6}'|sort |uniq -c |sort -rn
方法三:
netstat -n|awk '/^tcp/ {++S[$NF]} END {for (a in S) print a,S[a]}'