语法格式
awk [option] 'pattern{action}' file
awk [参数] '条件{动作}' 文件
awk命令的参数选项
- -F 指定字段分隔符
- -v 定义或修改一个awk内部的变量
awk命令的常见功能
# 直接取出显示出日志文件的url的这一列
awk -F "GET|HTTP" '{print $2}' access.log
# 分析生产环境中的日志找出谁在破解用户密码
awk '$6~/Failed/{print $11}' /var/log/secure
# 显示文件的20到30行
awk 'NR==20,NR==30' filename
# 计算总和
awk '{sum+=$0}END{print sum}' test.txt
# 对日志进行统计与计数
awk '{array[$1]++}END{for(key in array)print key,array[key]}' access.log
指定分隔符显示某几列
# 输出passwd的每一行
awk '{print $0}' /etc/passwd
# 针对每行以‘:’为分割符,输出第一项
awk -F":" '{ print $1 }' /etc/passwd
# 针对每行以‘:’为分割符,输出第一项和第二项
awk -F":" '{ print $1 $3 }' /etc/passwd
# 针对每行以‘:’为分割符,输出第一项和第二项,并格式化输出
awk -F":" '{ print $1 " " $3 }' /etc/passwd
awk -F":" '{ print "username: " $1 " uid:" $3 }' /etc/passwd
BEGIN和END模块
- 在 awk 开始处理输入文件中的文本之前,执行初始化代码(BEGIN内的代码块)。
- awk 在处理了输入文件中的所有行之后执行END块。
- END 块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。
赋值运算符
[root@yum tmp]# awk 'BEGIN{a=5;a+=5;print a}'
10
逻辑运算符
[root@yum tmp]# awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'
0 1
正则运算符
[root@yum tmp]# awk 'BEGIN{a="100testaaa";if(a~/100/){print "ok"}}'
ok
[root@yum tmp]# echo|awk 'BEGIN{a="100testaaa"}a~/100/{print "ok"}'
ok
关系运算符
- 其 > < 可以作为字符串比较,也可以用作数值比较,
- 关键看操作数如果是字符串,就会转换为字符串比较。
- 两个都为数字 才转为数值比较。
- 字符串比较:按照ascii码顺序比较。
[root@yum tmp]# awk 'BEGIN{a=11;if(a>=9){print "ok"}}'
ok
[root@yum tmp]# awk 'BEGIN{a;if(a>=b){print "ok"}}'
ok
算术运算符
- 所有用作算术运算符进行操作,操作数自动转为数值,
- 所有非数值都变为0。
[root@yum tmp]# awk 'BEGIN{a="b";print a++,++a}'
0 2
[root@yum tmp]# awk 'BEGIN{a="20b4";print a++,++a}'
20 22
其他运算符
[root@yum tmp]# awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'
ok
[root@yum tmp]# awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'
err
awk内置变量
变量名 |
属性 |
$0 |
当前记录 |
$1~$n |
当前记录的第n个字段 |
FS |
输入字段分隔符,默认是空格 |
RS |
输入记录分隔符,默认为换行符 |
NF |
当前记录中的字段个数,就是有多少列 |
NR |
已经读出的记录数,就是行号,从1开始 |
OFS |
输出字段分割符,默认是空格 |
ORS |
输出记录分隔符,默认为换行符 |
字段分隔符 FS
[root@yum tmp]# cat tab.txt
ww CC IDD
[root@yum tmp]# awk 'BEGIN{FS=" +"}{print $1,$2,$3}' tab.txt
ww CC IDD
- FS="[[:space:]+]" 一个或多个空白空格,默认的
[root@yum tmp]# cat space.txt
we are studing awk now!
[root@yum tmp]# awk -F [[:space:]+] '{print $1,$2}' space.txt
we are
- FS="[" ":]+" 以一个或多个空格或:分隔
[root@yum tmp]# cat hello.txt
root:x:0:0:root: /root:/bin/bash
[root@yum tmp]# awk -F [" ":]+ '{print $1,$2,$3}' hello.txt
root x 0
字段数量 NF
- 已":"为分隔符,分隔字段数量NF为8个则输出该行
[root@yum tmp]# cat hello.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin:888
[root@yum tmp]# awk -F ":" 'NF==8{print $0}' hello.txt
bin:x:1:1:bin:/bin:/sbin/nologin:888
记录数量 NR
[root@yum tmp]# ifconfig eth0| awk -F [" ":]+ 'NR==2{print $4}'
192.168.10.10
RS 记录分隔符变量
- 将 FS 设置成"
"告诉 awk 每个字段都占据一行。
- 通过将 RS 设置成"",告诉 awk每个地址记录都由空白行分隔。
[root@yum tmp]# cat recode.txt
Jimmy the Weasel
100 Pleasant Drive
San Francisco, CA 12345
#此处是空白行
Big Tony
200 Incognito Ave.
Suburbia, WA 67890
[root@yum tmp]# cat awk.txt
#!/bin/awk
BEGIN {
FS="
"
RS=""
}
{
print $1 ", " $2 ", " $3
}
[root@yum tmp]# awk -f awk.txt recode.txt
Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345
Big Tony, 200 Incognito Ave., Suburbia, WA 67890
OFS 输出字段分隔符
[root@yum tmp]# cat hello.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin:888
[root@yum tmp]# awk 'BEGIN{FS=":"}{print $1","$2","$3}' hello.txt
root,x,0
bin,x,1
[root@yum tmp]# awk 'BEGIN{FS=":";OFS="#"}{print $1,$2,$3}' hello.txt
root#x#0
bin#x#1
ORS 输出记录分隔符
[root@yum tmp]# cat recode.txt
Jimmy the Weasel
100 Pleasant Drive
San Francisco, CA 12345
Big Tony
200 Incognito Ave.
Suburbia, WA 67890
[root@yum tmp]# cat awk.txt
#!/bin/awk
BEGIN {
FS="
"
RS=""
ORS="
"
}
{
print $1 ", " $2 ", "$3
}
[root@yum tmp]# awk -f awk.txt recode.txt
Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345
Big Tony, 200 Incognito Ave., Suburbia, WA 67890
规则表达式
- awk '/REG/{action} ' file
- /REG/为正则表达式,
- 可以将$0 中,满足条件的记录送入到:action 进行处理
[root@yum tmp]# awk '/root/{print $0}' passwd
root:x:0:0:root: /root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@yum tmp]# awk -F : '$5~/root/{print $0}' passwd
root:x:0:0:root: /root:/bin/bash
[root@yum tmp]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print $4}' #取出 ip
192.168.10.10
[root@yum tmp]# ifconfig eth0|awk 'BEGIN{FS="([[:space:]]|:)+"} NR==2{print $4}' #取出 ip
192.168.10.10
布尔表达式
- awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。
[root@yum tmp]# awk -F: '$1=="root"{print $0}' passwd
root:x:0:0:root: /root:/bin/bash
[root@yum tmp]# awk -F: '($1=="root")&&($5=="root"){print $0}' passwd
root:x:0:0:root: /root:/bin/bash
条件语句
{
if ( $1== "foo" ) {
if ( $2== "foo" ) {
print "uno"
} else {
print "one"
}
} elseif ($1== "bar" ) {
print "two"
} else {
print "three"
}
}
循环结构
do...while循环
{
count=1
do {
print "I get printed at least once no matter what"
} while ( count !=1 )
}
for 循环
{
for ( x=1;x<=4;x++ ) {
print "iteration", x
}
}
break和continue
{
x=1
while (1) {
if ( x==4 ) {
x++
continue
}
print "iteration", x
if ( x>20 ) {
break
}
x++
}
数组
{
cities[1]=”beijing”
cities[2]=”shanghai”
cities[“three”]=”guangzhou”
for( c in cities) {
print cities[c]
}
print cities[1]
print cities[“1”]
print cities[“three”]
}
例子
查看服务器连接状态并汇总
netstat -an|awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}'
统计 web 日志访问流量
要求输出访问次数
请求页面或图片
每个请求的总大小
总访问流量的大小汇总
awk '{a[$7]+=$10;++b[$7];total+=$10}END{for(x in a)print b[x],x,a[x]|"sort -rn -k1";print
"total size is :"total}' access_log
a[$7]+=$10表示以第7列为下标的数组($10列为$7列的大小)
把他们大小累加得到$7每次访问的大小
后面的for循环有个取巧的地方,a和b数组的下标相同
所以一条for语句足矣
awk常用函数
函数 |
说明 |
gsub( Ere, Repl, [ In ] ) |
除了正则表达式所有具体值被替代这点,它和 sub 函数完全一样地执行。 |
sub( Ere, Repl, [ In ] ) |
用 Repl 参数指定的字符串替换 In 参数指定的字符串中的由 Ere参数指定的扩展正则表达式的第一个具体值。 sub 函数返回替换的数量。出现在 Repl 参数指定的字符串中的 &(和符号)由 In 参数指定的与 Ere 参数的指定的扩展正则表达式匹配的字符串替换。如果未指定 In 参数,缺省值是整个记录( $0 记录变量)。 |
index( String1, String2 ) |
在由 String1 参数指定的字符串(其中有出现 String2 指定的参数)中,返回位置,从 1 开始编号。如果 String2 参数不在 String1 参数中出现,则返回 0(零)。 |
length [(String)] |
返回 String 参数指定的字符串的长度(字符形式)。如果未给出String 参数,则返回整个记录的长度( $0 记录变量)。 |
blength [(String)] |
返回 String 参数指定的字符串的长度(以字节为单位)。如果未给出String 参数,则返回整个记录的长度( $0 记录变量)。 |
substr( String, M, [ N ] ) |
返回具有 N 参数指定的字符数量子串。子串从 String 参数指定的字符串取得,其字符以 M 参数指定的位置开始。 M 参数指定为将String 参数中的第一个字符作为编号 1。如果未指定 N 参数,则子串的长度将是 M 参数指定的位置到 String 参数的末尾 的长度。 |
match( String, Ere ) |
在 String 参数指定的字符串( Ere 参数指定的扩展正则表达式出现在其中)中返回位置(字符形式),从 1 开始编号,或如果 Ere 参数不出现,则返回 0 (零)。 RSTART 特殊变量设置为返回值。 RLENGTH特殊变量设置为匹配的字符串的长度,或如果未找到任何匹配,则设置为 -1(负一)。 |
split( String, A, [Ere] ) |
将 String 参数指定的参数分割为数组元素 A[1], A[2], . . ., A[n],并返回 n 变量的值。此分隔可以通过 Ere 参数指定的扩展正则表达式进行,或用当前字段分隔符( FS 特殊变量)来进行(如果没有给出 Ere参数)。除非上下文指明特定的元素还应具有一个数字值,否则 A 数组中的元素用字符串值来创建。 |
tolower( String ) |
返回 String 参数指定的字符串,字符串中每个大写字符将更改为小写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。 |
toupper( String ) |
返回 String 参数指定的字符串,字符串中每个小写字符将更改为大写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。 |
sprintf(Format, Expr,Expr, . . . ) |
根据 Format 参数指定的 printf 子例程格式字符串来格式化 Expr参数指定的表达式并返回最后生成的字符串。 |
替换
awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}' this is a test!test!
在info中查找满足正则表达式,/[0-9]+/用”!”替换,并且替换后的值,赋值给 info未给info值,默认是$0
查找
awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok
#未找到,返回 0
匹配查找
awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'ok
#如果查找到数字则匹配成功返回 ok,否则失败,返回未找到
截取
awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'s is a tes
#从第 4 个 字符开始,截取 10 个长度字符串
分割
awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 44 test 1 this 2 is 3 a
#分割info,动态创建数组tA,awk for …in 循环,是一个无序的循环。并不是从数组下标1…n 开始