awk

 

基础理论

awk脚本是由模式和操作(动作)组成的

 

模式

 

模式可以是以下任意一个:

 1. /正则表达式/:使用通配符的扩展集。

 2.关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试。

 3. 模式匹配表达式:用运算符~(匹配)和~!(不匹配)。

 4.BEGIN语句块、pattern语句块、END语句块:

  

动作:

 1.变量或数组赋值

 2.输出命令

 3.内置函数

 4.控制流语句

 

 

awk基本结构

 

一个awk脚本通常由:

1. BEGIN语句块

2.能够使用模式匹配的通用语句块。

3. END语句块  3部分组成。

 

格式如下:

awk 'BEGIN{BEGIN部分的执行内容}{通用语句部分}END{结束后执行的内容}' 文件名

 

解释:

每一部分(除了BENGIN、END关键字外)都需要用{}扩起来。来区分这3个不同的部分。

 

例子:

awk 'BEGIN{print "---"}{print "china"}END{print "---"}' /etc/fstab

执行结果如下:

---

china

china

china

china

---

 

解释:

1、 BEGIN{print "---"}为第一部分,BENGIN标识了后边括号中的内容为begin部分

2、 {print "china"}为第二部分,通用语句块部分

3、 END{print "---"}为第三部分,END标识了后边大括号中的内容为END部分的内容

 

结束后要执行的语句块。

  

这三个部分是可选的。任意一个部分都可以不出现在脚本中,脚本通常是被单引号双引号中.

 

例子1

 只出现BEGIN部分

 [root@centos-1 ~]# awk 'BEGIN{print "---"}'

 --

 需要注意:

 只出现BEGIN部分,后边不需要跟文件名

 

例子2

只出现通用语句块部分

[root@centos-1 ~]# awk '{print "china"}' /etc/fstab

china

china

china

china

china

china

需要注意:

只出现通用语句块部分,后边必须跟文件名。没有文件名不能正常处理

 

例子3

只出现END语句块部分

[root@centos-1 ~]# awk 'END{print "---"}' /etc/fstab

---

需要注意:

只出现END语句块部分,后边必须跟文件名。没有文件名不能正常处理

 

awk工作流原理

第一步:执行BEGIN{}语句块中的语句;

 第二步:从文件或标准输入(stdin)读取一行,然后执行{通用语句块}语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。

 第三步:当读至输入流末尾时,执行END{}语句块。

  

BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。

 

END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。

 

pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。

常看awk版本

[root@localhost pangbing]# awk -W version

GNU Awk 3.1.7

Copyright (C) 1989, 1991-2009 Free Software Foundation.

 


2.域和记录
    

域可以理解为”列”
在默认情况下,awk把文件按照空格分成不用的域(也就是列),

 

域的标记为$1 $2 $3.....。这种方法称为域标识。

 

 $0表示所有域。例子:awk '{print $0}' 文件名

 

 我们也可以通过-F选项来指定分割符,根据这个分割符把文件分成不同的域

    
例子:awk '{print $0}' 文件名 > 文件名 | tee 文件名

管道前边的结果会直接输出到文件,不会输出到屏幕上。tee命令就是能同时让结果输出到屏幕上。

   打印不同的域,中间用逗号隔开

     例子:'{print$1,$3,$7}'


3.awk 匹配正则表达式
    
     元字符:
          这里是 a w k中正则表达式匹配操作中经常用到的字符:

          ^ $ . [] [^] | () * + ?
     条件操作符

     表9 - 2给出a w k条件操作符,后面将给出其用法。
    
     表9-2 awk条件操作符
     操 作 符     描 述          操 作 符      描 述

     <            小于              >=           大于等于

     <=           小于等于          ~           匹配正则表达式

     ==           等于            !~          不匹配正则表达式

     !=            不等于

<1>  匹配
     为使某一域号匹配正则表达式,使用符号‘~’后紧跟正则表达式
    
     例子:

awk  /root/ /etc/passwd 这个是简单的写法 ;passwd文件中只要含有root的行就打印出来

root:x:0:0:root:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

    

awk -F:  '$1~/root/' /etc/passwd 意思是以:

为分隔符号,打印第一段(区域)匹配含有root的行

root:x:0:0:root:/root:/bin/bash

 

awk -F: '$3~/0/' /etc/passwd 意思是以:为分隔符号,打印第三段(区域)匹配含有0的行

 

awk -F: '$3=="0"' /etc/passwd 意思是以:为分隔符号,打印第三段(区域)匹配是0的行(这时精确匹配)

awk '/^ /' 文件名      匹配以空格开头的行

awk '/^ | ^#/' httpd.conf 匹配空格开头的或者是^#开头的

awk '!(/表达式1/&& /表达式2/)' /etc/passwd

表示取反

 

 

<2>.  精确匹配

为精确匹配 48,使用等号 ==并用单引号括起条件。例如 $3==“48” ,这样确保只有 4 8序号得以匹配,其余则不行。

awk -F: '$3~/0/' /etc/passwd 意思是以:为分隔符号,打印第三段(区域)匹配含有0的行

    

root:x:0:0:root:/root:/bin/bash

uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin

     pangbing:x:500:500:pangbing:/home/pangbing:/bin/bash

    

awk -F: '$3=="0"' /etc/passwd 意思是以:为分隔符号,打印第三段(区域)匹配只是0的行(这是精确匹配)

                                                          ################
     root:x:0:0:root:/root:/bin/bash    

<3> 不匹配
     awk -F: '$3!="0"' /etc/passwd
     awk -F: '$3!~/0/' /etc/passwd
<4>比较

     awk -F: '$3>=$4'  /etc/passwd

 

4.计算

     

     [root@localhost pangbing]# cat 1

          1  11

          2  12

          3  14

          4  22

    

     <1>求和

    格式: awk '{变量名+=第几列}END{print 变量名}' 文件名

     [root@localhost pangbing]#

      awk  '{sum+=$1}END{print sum}' 1

          10

     [root@localhost pangbing]#

      awk '{sum+=$2}END{print sum}' 1

          59

    

     <2>求平均值

     格式:awk '{变量名+=第几列}END{print 变量名/NR}' 文件名

    

     [root@localhost pangbing]# awk    '{a+=$2}END{print a/NR}' 1

          14.75

 

5.多条件同时匹配

     [root@localhost pangbing]# cat 1

          1  11 

          1  12 asd fff

          1  13 2

    

     同时匹配多个条件

     格式:awk '条件1 && 条件2 && 条件...' 文件名

     [root@localhost pangbing]#

awk '$1~/1/ && $2~/12/' 1     

awk '$1~"1" && $2~"12"' 1    //也可以用""代替

          1  12 asd fff

    

     <1>前提是用 匹配时可以用双引号替换//

          

     <2>/表达式/单独出现时,不要用双引号替换,结果会有误。

 

时间段匹配

 

[root@centos-1 ~]# cat c
10:01
10:02
10:03
10:05
10:06
10:07
12:01
11:01

 

[root@centos-1 ~]# awk '$1>="10:05" && $1<="11:10"' c
10:05
10:06
10:07
11:01

awk的时间匹配是不受时间顺序的影响

 

[root@centos-1 ~]# awk '/10:05/,/11:10/' c
10:05
10:06
10:07
12:01
11:01

而这种匹配是受数值顺序的影响的,这里需要特别注意

 

                                        

6.awk中的for循环

          [root@localhost pangbing]# cat b

                 pppppp

    

     

     

     例子:[root@localhost pangbing]# awk '{for (i=1;i<=10;i++) print i}' b

             1

                           2

                           3

                           4

 

    

     其中

     for(i=1;i<=10;i++)循环的意思是:定义了一个取值列表

     for (变量=开始;停止循环的条件;步进长度)

     停止循环的条件:是指满足条件就循环,不满足就停止循环。

     误区我这个循环理错了:

          i做一次赋值运算,然后用i<=10这个条件判断i的值是不是小于10,然后做i的值做+1运算,然后i在从新赋值等于1,判断,运算。然后i在从新赋值等于1,判断,运算。我是这样错误理解这个循环的。这样i不是永远都 等于2了。

     正确理解:这里边真正的循环体是i=1

               i<=10i++是给i=1循环时候添加的附加条件

               i++定义了 i 循环时候的运算方式。是说你每次循环都加1

               i<=10 :那么加到什么时候为止呢,i不在小于等于10的时候就停止循环。

    

     循环过程:i=1 判断是否满足条件,满足就1+1

              这时i=2了。还满足条件  2+1

              这时i=3.还满足条件  3+1

              一直循环到不满足条件为止。

    <2>另一种for的写法

          这种写法和shell一样

          fori in 取值列表)

4.  awk内置变量

     a w k有许多内置变量用来设置环境信息。这些变量可以被改变。表 9 - 3显示了最常使用的
     一些变量,并给出其基本含义
     A R G C 命令行参数个数
     A R G V 命令行参数排列
     E N V I R O N 支持队列中系统环境变量的使用
     FILENAME  a w k浏览的文件名
     F N R 浏览文件的记录数
     F S 设置输入域分隔符,等价于命令行 - F选项
     N F 浏览记录的域个数$NF表示最后一段。)
     N R 已读的记录数

     O F S 输出域分隔符
     O R S 输出记录分隔符
     R S 控制记录分隔符

 

5.ifconfig eth0 | awk  -F[" ":]+ '/inet addr/ {print $4}'

这是快速过滤出IP地址的方法

 

 

echo 1234567890|awk -F "^C'{print $5}'

5

 

awk '{print $1,$NF,$(NF-1),$RS,$(NR-1),$(NR+1)}'

  

统计ip次数

awk '{print $1}' a.log |sort|uniq -c|sort -nr

优化后

awk '{a[$1]++}END{for (i in a)print a[i],i}'|sort -nr

 

*

a[$i]++

创建一个哈希数组,数组的key是每一列的内容a1、b1、a1、c1......,数组的value是每一列出现的次数

 

awk 哈希数组

 

awk  printf 制表符

 

过滤ip地址

grep -o '([0-9]{1,3}.){3}[0-9]{1,3}' urfile

 

原文地址:https://www.cnblogs.com/pangbing/p/6535652.html