语法格式
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 "\t\tuid:" $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="\t+"}{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 设置成"\n"告诉 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="\n"
    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="\n"
    RS=""
    ORS="\n\n"
} 
{
    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 开始
05-Linux文本处理-awk
原文:https://www.cnblogs.com/liangjingfu/p/9419412.html