【awk终极总结】

awk简介

awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
awk 是一种很棒的语言,它适合文本处理报表生成,其语法较为常见,借鉴了某些语言的一些精华,如 C 语言等。在 linux 系统日常处理工作中,发挥很重要的作用,掌握了 awk将会使你的工作变的高大上。 awk 是三剑客的老大,利剑出鞘,必会不同凡响。

使用方法

awk  [option]  ' [pattern]{pattern_block}  {block1} {block2} [pattern]{pattern_block}'  filenames
# 这里写的pattern一般是BEGIN和END
#BEGIN后的代码块是处理文件之前的代码
#END后的代码块是处理完文件之后的代码
# 中间的blocks们是处理每一行时要执行的语句t

实例:
vth_zz.txt中的内容:

vth_zz

代码:

awk -F '_' 'BEGIN{print("a")}{print($1)}{print($2)}' vth_zz.txt

结果:

a
vth
zz

当然啦,也可以用|把前面cat到的东西给awk
注意awk是逐行操作的,意思就是所有的代码都是对某一行进行处理的,从文件头执行到文件尾。
对于print语句来说,$0代表整行,$1代表第一个字段值…以此类推。$NF代表最后一个字段的值,为啥呢?因为每一行的字段数(什么叫字段数?就是分割之后,有多少段就是字段数)在awk中是NF,那么$NF自然就是最后一个字段的值啦。同理,$(NF-1)就是倒数第二个字段的值。
-F参数的意思是分隔符,-F后面的字符串'xxx'就是分隔符(按照xxx进行分割,也就是说不只是一位,还可以是多位)。
如果想按照多种字符进行分割,可以'[ -]'这样,这样的意思就是遇到空格也分,遇到-也分。跟正则差不多。
也可以这样玩'[ _]z',意思是遇到' z'要分割,遇到_z也要分割。

BEGIN 和 END 模块

通常,对于每个输入行, awk 都会执行每个脚本代码块一次。然而,在许多编程情况中,可能需要在 awk 开始处理输入文件中的文本之前执行初始化代码。对于这种情况, awk 允许您定义一个 BEGIN 块。
因为 awk 在开始处理输入文件之前会执行 BEGIN 块,因此它是初始化 FS(字段分隔符)变量、打印页眉或初始化其它在程序中以后会引用的全局变量的极佳位置。
awk 还提供了另一个特殊块,叫作 END 块。 awk 在处理了输入文件中的所有行之后执行这个块。通常, END 块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。

awk运算符

在这里插入图片描述
awk中,代码块中的多行语句可以用;进行分割,多个参数可以用,进行分割。
awk 赋值运算符:a+=5;等价于: a=a+5;其他同类

[root@Gin scripts]# awk 'BEGIN{a=5;a+=5;print a}'
10

awk逻辑运算符:

[root@Gin scripts]# awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'
0 1

为真输出1,为假输出0

awk正则运算符:

[root@Gin scripts]# awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'
ok
[root@Gin scripts]# echo|awk 'BEGIN{a="100testaaa"} {if(a~/test/){print "ok"}}'
ok

正则运算符的用法:

/这里写正则表达式就可以啦/ 
判断是不是匹配用 ~ 和 !~

解释:

Q:为什么第一条语句都写在BEGIN块中?
A:因为写在BEGIN块中不需要给awk指定一个文件,用作写DEMO再合适不过了
Q:为什么第二条语句要这么写?
A:这个演示了awk接受|过来的东西时的处理流程

关系运算符:
如: > 和< 可以作为字符串比较,也可以用作数值比较,关键看操作数。如果是字符串就会转换为字符串比较。两个都为数字才转为数值比较。字符串比较:按照ascii码顺序比较。

[root@Gin scripts]# awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出
[root@Gin scripts]# awk 'BEGIN{a=11;if(a>=9){print "ok"}}' 
ok
[root@Gin scripts]# awk 'BEGIN{a;if(a>=b){print "ok"}}'
ok

awk 算术运算符:
说明,所有用作算术运算符进行操作,操作数自动转为数值,所有非数值都变为0

[root@Gin scripts]# awk 'BEGIN{a="b";print a++,++a}'
0 2
[root@Gin scripts]# awk 'BEGIN{a="20b4";print a++,++a}'
20 22

这里的a++ , ++a 与c语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?:

[root@Gin scripts]# awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'
ok
[root@Gin scripts]# awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'
err

常用 awk 内置变量

在这里插入图片描述
字段分隔符 FS
FS="\t" # 使FS代表的分隔符变成一个或多个 Tab 分隔
其实FS-F参数差不多,会一个就行。

[root@Gin scripts]# cat tab.txt
ww   CC        IDD
[root@Gin scripts]# awk 'BEGIN{FS="\t+"}{print $1,$2,$3}' tab.txt
ww   CC        IDD

FS="[" ":]+" 以一个或多个空格或:分隔

[root@Gin scripts]# cat hello.txt
root:x:0:0:root:/root:/bin/bash
[root@Gin scripts]# awk -F '[" ":]'+ '{print($1,$2,$3)}' hello.txt
root x 0

字段数量 NF

[root@Gin scripts]# cat hello.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin:888
[root@Gin scripts]# awk -F ':' '{if(NF==8){print($0)}}' hello.txt
bin:x:1:1:bin:/bin:/sbin/nologin:888

记录数量 NR

[root@Gin scripts]# ifconfig eth0|awk -F '[" ":]+'  '{if(NR==2){print($4)}}'  ## NR==2也就是取第2行
192.168.17.129
# 意思就是按照1个或者多个空格或者1个或者多个:来进行分隔

RS 记录分隔符变量
FS 设置成"\n"告诉 awk 目前的文档中每个字段都占据一行。通过将 RS 设置成"",还会告诉 awk目前的文档中每个地址记录都由空白行分隔。

[root@Gin scripts]# cat recode.txt
Jimmy the Weasel
100 Pleasant Drive
San Francisco,CA 123456
 
Big Tony
200 Incognito Ave.
Suburbia,WA 64890
[root@Gin scripts]# cat awk.txt
#!/bin/awk
BEGIN {
        FS="\n"
        RS=""
}
{
        print $1","$2","$3
}
[root@Gin scripts]# awk -f awk.txt recode.txt
Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456
Big Tony,200 Incognito Ave.,Suburbia,WA 64890

OFS 输出字段分隔符

[root@Gin scripts]# cat hello.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin:888
[root@Gin scripts]# awk 'BEGIN{FS=":"}{print $1","$2","$3}' hello.txt
root,x,0
bin,x,1
[root@Gin scripts]# awk 'BEGIN{FS=":";OFS="#"}{print $1,$2,$3}' hello.txt
root#x#0
bin#x#1

即通过修改OFS来达到替换字段分隔符的目的
ORS 输出记录分隔符

[root@Gin scripts]# cat recode.txt
Jimmy the Weasel
100 Pleasant Drive
San Francisco,CA 123456
 
Big Tony
200 Incognito Ave.
Suburbia,WA 64890
[root@Gin scripts]# cat awk.txt
#!/bin/awk
BEGIN {
        FS="\n"
        RS=""
        ORS="\n\n"
}
{
        print $1","$2","$3
}
[root@Gin scripts]# awk -f awk.txt recode.txt
Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456
 
Big Tony,200 Incognito Ave.,Suburbia,WA 64890

修改ORS来达到修改每一行的分隔符的目的。

awk 正则

在这里插入图片描述
规则表达式
awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

[root@Gin scripts]# awk '/root/{print $0}' passwd ##匹配所有包含root的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
 
[root@Gin scripts]# awk -F: '$5~/root/{print $0}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行
root:x:0:0:root:/root:/bin/bash
 
[root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print $4}'
192.168.17.129

布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。

[root@Gin scripts]# awk -F: '$1=="root"{print $0}' passwd
root:x:0:0:root:/root:/bin/bash
[root@Gin scripts]# awk -F: '($1=="root")&&($5=="root") {print $0}' passwd
root:x:0:0:root:/root:/bin/bash

awk 的 if、循环和数组

条件语句
awk 提供了非常好的类似于 C 语言的 if 语句。

{
        if ($1=="foo"){
                if($2=="foo"){
                        print "uno"
                }else{
                        print "one"
                }
        }elseif($1=="bar"){
                print "two"
        }else{
                print "three"
        }
}

使用 if 语句还可以将代码:

! /matchme/ { print $1 $3 $4 }

转换成:

{
  if ( $0 !~ /matchme/ ) {
    print $1 $3 $4
  }
}

循环结构
我们已经看到了 awkwhile 循环结构,它等同于相应的 C 语言 while 循环。 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。
它类似于其它语言中的"repeat...until"循环。以下是一个示例:
do...while 示例

{
    count=1do {
        print "I get printed at least once no matter what"
    } while ( count !=1 )
}

与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。
for 循环
awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

for ( initial assignment; comparison; increment ) {
    code block
}

以下是一个简短示例:

for ( x=1;x<=4;x++ ) {
    print "iteration", x
}

此段代码将打印:

iteration1
iteration2
iteration3
iteration4

breakcontinue
此外,如同 C 语言一样, awk 提供了 breakcontinue 语句。使用这些语句可以更好地控制 awk 的循环结构。以下是迫切需要 break 语句的代码片断:

while 死循环
while (1) {
print "forever and ever..."
}
while 死循环 1 永远代表是真,这个 while 循环将永远运行下去。

以下是一个只执行十次的循环:

#break 语句示例
x=1
while(1) {
  print "iteration", x
  if ( x==10 ) {
    break
  }
  x++
}

这里, break 语句用于“逃出”最深层的循环。 "break"使循环立即终止,并继续执行循环代码块后面的语句。
continue 语句补充了 break,其作用如下:

x=1while (1) {
        if ( x==4 ) {
        x++
        continue
    }
    print "iteration", x
    if ( x>20 ) {
        break
    }
    x++
}

这段代码打印"iteration1""iteration21""iteration4"除外。如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。如同 break 一样,

continue 语句适合各种 awk 迭代循环。在 for 循环主体中使用时, continue 将使循环控制变量自动增加。以下是一个等价循环:

for ( x=1;x<=21;x++ ) {
    if ( x==4 ) {
        continue
    }
    print "iteration", x
}

for 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。

数组
awk 中的数组都是关联数组,数字索引也会转变为字符串索引

{
    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”]
}

for…in 输出,因为数组是关联数组默认是无序的。所以通过 for…in 得到是无序的数组。如果需要得到有序数组,需要通过下标获得
数组的典型应用
awk 中查看服务器连接状态并汇总

netstat -an|awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}'
ESTABLISHED 1
LISTEN 20

统计 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}' /app/log/access_log
total size is :172230
21 /icons/poweredby.png 83076
14 / 70546
8 /icons/apache_pb.gif 18608
a[$7]+=$10 表示以第 7 列为下标的数组( $10 列为$7 列的大小),把他们大小累加得到
$7 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一
条 for 语句足矣

常用字符串函数

在这里插入图片描述
在这里插入图片描述
字符串函数的应用
替换

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];}}' 4
4 test 1 this 2 is 3 a
#分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。 并不是从数组下标
1…n 开始

猜你喜欢

转载自blog.csdn.net/weixin_41687289/article/details/88896677
今日推荐