1. 程序结构: Begin 和 End模块

 

 

awk的程序的结构:Begin块,Body块,End块。

  • BEGIN块:BEGIN {awk-commands}
    • BEGIN块在被程序启动时启动,且只执行一次。
    • 这是一个很好的初始化变量的地方,常常被用来修改内置变量RS,FS,OFS,ORS等的值。
    • BEGIN是awk的关键字,必须大写。
    • 可选的
  • BODY块:  /pattern/{awk-commands(action)}
    • 主体块适用于awk的每个输入行命令。
    • 默认情况下,awk执行每一行命令,但可以通过pattern限制。
    • body块没有关键字
  • END块: END {awk-commands}
    • END块在程序结束时执行,在awk读取完所有的文件的时候,再执行的。
    • 一般用来输出一个结果(累加,数组结果)
    • END是awk关键字,必须是大写。
    • 可选的。
[root@oldboy test]# awk 'BEGIN {print "Sr No Name Sub Marks\t"} {print} END{print "****END***"}' marks.txt 
Sr No Name Sub Marks
1) Amit Physics 80
2) Rahul Maths 90
3) Shyam Biology 87
4) Kedar English 85
5) Hari History 89
****END***

 

案例:统计文件里面的空行数量

# grep查看文件内的空行数量
[root@oldboy test]# grep -c '^$' /etc/services 16

# 遇到空行print 数量(增量+1) [root@oldboy test]# awk '/^$/{a=a+1;print a}END{print "Blank Record Count:",a}' /etc/services 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Blank Record Count: 16
# 仅输出END块,空行数量
[root
@oldboy test]# awk '/^$/{a=a+1} END{print "Blank Record Count:",a}' /etc/services
Blank Record Count: 16

 

问题: awkfile2.txt 里面 以:为分隔符,区域3 大于15,一共有多少个?

 awk -F ":" '$3>15{a=a+1} END{print a}' awkfile2.txt

 

示例:找出环境变量$PATH中,所有只有三个任意字符的命令,例如:tee,并将它们重定向到command.txt中,要求一行显示1个,并在文件尾部统计他们的个数。

find `echo $PATH|tr ":" " "` -type f -name "???"|awk '{cnt+=1;print $0} END{print "Total Count:",cnt}' >>command.txt

 

示例:1+2+...+100,加到100的值,用awk实现。

  • awk '{if (a<100) {++a;b+=a;print a,b}}' /etc/services
  • awk 'BEGIN {for (i=1;i<101;++i) {s+=i;print s}}'|tail -1
  • echo |awk 'BEGIN {for (i=1;i<101;++i) {s+=i}} END{print s}' 

 

2. awk数组

  • 数组的索引不必是连续的设定的值;
  • 可以使用字符串或数字作为数组的索引
  • 不需要事先声明数组的大小
  • 数组可以在运行时扩展/收缩

 

数组的语法:

    array_name[index] = value

其中,array_name是数组的名称,index是数组索引,value是任意值分配给数组的元素。

 

2.1 创建 array_name[index] = value

[root@oldboy test]# awk 'BEGIN{fruits["mango"]="yellow";fruits["orange"]="orange";print fruits["orange"] "\n" fruits["mango"]}'  
orange
yellow

 

 

2.2 删除 delete array_name[index]

使用delete语句从数组中删除元素。

[root@oldboy test]# awk 'BEGIN{fruits["mango"]="yellow";fruits["orange"]="orange";delete fruits["orange"];print fruits["mango"];print fruits["orange"]}'
yellow

[root@oldboy test]# 

 

 

2.3 多维数组:用一维数组模拟多维数组

awk只支持一维数组,但是我们可以很容易地模拟使用一维阵列本身的多维阵列。 

例如下面是3×3的三维阵列:

100 200 300
400 500 600
700 800 900

 

另外,在上述示例array[0] [0]存储100,array[0][1]存储200等。要在位置array[0] [0]存储100,我们可以使用下面的语法:

array["0,0"] = 100

 

虽然我们已经给定0,0为索引,这些都不是两个索引。在现实中,它只是一个索引以字符串0,0。

下面简单的例子模拟2-D数组:

awk 'BEGIN {
array["0,0"] = 100;
array["0,1"] = 200;
array["0,2"] = 300;
array["1,0"] = 400;
array["1,1"] = 500;
array["1,2"] = 600;
# print array elements
print "array[0,0] = " array["0,0"];
print "array[0,1] = " array["0,1"];
print "array[0,2] = " array["0,2"];
print "array[1,0] = " array["1,0"];
print "array[1,1] = " array["1,1"];
print "array[1,2] = " array["1,2"];
}'

 

在执行上面的代码后,得到以下结果:
array[0,0] = 100
array[0,1] = 200
array[0,2] = 300
array[1,0] = 400
array[1,1] = 500
array[1,2] = 600

 

我们还可以在排序其元素/索引于阵列执行各种操作。

为了达到这个目的,可以使用AWK的asort以及asorti函数。我们将看到在后面的章节这些函数的使用。

 

2.4 无序和有序的关联数组

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

[root@oldboy test]# awk 'BEGIN {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"]
> }'
guangzhou
beijing
shanghai
beijing
beijing
guangzhou

 

for循环的输出,因为数组是关联数组,默认是无序的。通过for循环得到的是无序的数组。

 

如果需要得到有序数组,需要通过下标指定获得。

 

2.5 awk数组的典型应用

案例:用awk查看服务器连接状态并汇总

[root@oldboy test]# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State      
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      
tcp        0      0 192.168.0.109:22            192.168.0.102:53242         ESTABLISHED 
tcp        0      0 :::80                       :::*                        LISTEN      
tcp        0      0 :::22                       :::*                        LISTEN      
udp        0      0 0.0.0.0:68                  0.0.0.0:*                               
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node Path
unix  2      [ ACC ]     STREAM     LISTENING     9885   /var/lib/mysql/mysql.sock
unix  2      [ ACC ]     STREAM     LISTENING     7111   @/com/ubuntu/upstart
unix  2      [ ]         DGRAM                    7512   @/org/kernel/udev/udevd
unix  5      [ ]         DGRAM                    9369   /dev/log
unix  2      [ ]         DGRAM                    209043 
unix  2      [ ]         DGRAM                    20157  
unix  2      [ ]         DGRAM                    9921   
unix  3      [ ]         DGRAM                    7530   
unix  3      [ ]         DGRAM                    7529   
[root@oldboy test]# netstat -an|awk '/^tcp/{++s[$NF]} END{for (a in s) print a,s[a]}'
ESTABLISHED 1
LISTEN 4

 

++s[$NF] 即将s作为数组的名称,索引是$NF,通过++s增量加1的方式,遇到一次s["Listen"]的值加1,非常的高校实用。

等价的表示方式为:

[root@oldboy test]# netstat -an|awk '/^tcp/{state[$NF]+=1;print s state[$NF] $NF} END{for (a in state) print a,state[a]}'
1LISTEN
2LISTEN
1ESTABLISHED
3LISTEN
4LISTEN
ESTABLISHED 1
LISTEN 4

 

 

案例:统计web日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总。

需要结合httpd服务的日志文件进行解析。

 

面试题:处理以下文件内容,将 域名计算计数 排序处理(去重)

http://www.etiantian.org/index.html
http://www.etiantian.org/1.html
http://post.etiantian.org/index.html
http://mp3.etiantian.org/index.html
http://www.etiantian.org/3.html
http://post.etiantian.org/2.html

 

答案:

[root@oldboy test]# awk -F "/" '{print $3}' html.txt |sort -rn|uniq -c
      3 www.etiantian.org
      2 post.etiantian.org
      1 mp3.etiantian.org
[root
@oldboy test]# awk -F "/" '{++domain[$3];print $3,domain[$3]}' html.txt www.etiantian.org 1 www.etiantian.org 2 post.etiantian.org 1 mp3.etiantian.org 1 www.etiantian.org 3 post.etiantian.org 2 [root@oldboy test]# awk -F "/" '{++domain[$3]} END{for (a in domain) print a,domain[a]}' html.txt mp3.etiantian.org 1 post.etiantian.org 2 www.etiantian.org 3

3. if语句

awk提供了类似C语言的if语句。

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

 

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

! /match pattern/ {print $1}

 

转换成:

{ 
    if ($0 !~/match pattern/) {
        print $1
    }    
}

 

 

if语句,它只是测试条件,并执行特定操作,这取决于条件。

if语句语法:

  if (conditon) action

  if (condition) {action1 action2 action3 ... action-n}

if-else语句语法:

  if (conditon) action-1 else action-2

if-else-if阶梯语法:

  if (condition1) action-1 else if (condition2) action2 else if (condtiton3) action3

示例:检查给定的数是否为偶数。

[root@oldboy test]# awk 'BEGIN{num=10;if (num%2==0) printf "%d is even number.\n",num}'
10 is even number.

 

[root@oldboy test]# awk 'BEGIN{num=10;if (num%2==0) printf "%d is even number.\n else",num; else printf "%d is odd number.\n",num}'
10 is even number.
 root@oldboy test]# awk 'BEGIN{num=9;if (num%2==0) printf "%d is even number.\n else",num; else printf "%d is odd number.\n",num}'  
9 is odd number.
# if-else-if 示例:
[root@oldboy test]# awk 'BEGIN { > a=30; > if (a==10) > print "a=10"; > else if (a==20) > print "a=20"; > else if (a==30) > print "a=30"; > }' a=30

 


 

4. 循环结构:for循环,while循环,do-while循环

4.1 for循环

for循环语法:

for (initalisation; condition; increment/decrement) action

 示例:

[root@oldboy test]# awk 'BEGIN{for (i=1;i<=5;++i) print i}'   # 初始化动作i=1;条件i<=5;增量或减量
1
2
3
4
5

 

 

4.2 while循环

while循环语法:

while (condition)
  action

 

 awk首先检查条件,如果条件为真,就执行操作,不断重复,只要循环条件满足为真。

[root@oldboy test]# awk 'BEGIN {i=1; while (i<6) {print i; ++i}}'          
1
2
3
4
5

 

 

4.3 do-while循环

do-while循环语法:

do
  action
while (condition)

do-while循环类似于while循环,不同之处在于测试条件是否在循环结束时进行计算。

 

do-while循环操作语句被执行至少一次,即使在条件语句的计算结果为假。

[root@oldboy test]# awk 'BEGIN{i=1; do {print i;++i} while (i<6)}'
1
2
3
4
5

 

 

4.4 break,continue,exit语句

  • break 结束循环的执行
  • continue 循环内跳到循环的下一次迭代
  • exit 停止脚本的执行。接受一个整数作为参数,这将是awk进程的退出状态代码。如果没有任何参数,则返回状态为0.
[root@oldboy test]# awk 'BEGIN{sum=0; for (i=0;i<20;++i) {sum +=i; if (sum>50) break; else print "Sum =",sum}} '
Sum = 0
Sum = 1
Sum = 3
Sum = 6
Sum = 10
Sum = 15
Sum = 21
Sum = 28
Sum = 36
Sum = 45

[root@oldboy test]# awk 'BEGIN{for (i=1; i<=20; ++i) {if (i%2==0) print i; else continue}}'      
2
4
6
8
10
12
14
16
18
20

[root@oldboy test]# awk 'BEGIN{sum=0; for (i=0;i<20;++i) {sum +=i; if (sum>50) exit(10); else print "Sum =",sum}}'
Sum = 0
Sum = 1
Sum = 3
Sum = 6
Sum = 10
Sum = 15
Sum = 21
Sum = 28
Sum = 36
Sum = 45

  [root@oldboy test]# echo $?  # 检查脚本的返回状态
  10

 

posted on 2019-11-24 19:34  Zoe233  阅读(209)  评论(0编辑  收藏  举报