我们知道, awk程序由一系列 pattern 以及与之对应的 action 组成的 rule 组成,rule之间用";"分号隔开, 一条输入记录与 pattern 匹配则执行与之关联的action, 如下所示:

awk ' 
        pattern { action };
        pattern { action };
        .....
'

可是, 很多人并不清楚什么东西可以做为 pattern下面就来聊聊这些个事儿. 以下文本做为测试文本:

$ cat myfile
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R

首先, 要记住, 凡是被 {} 包裹的, 就是 action, 或者说, action 必然被 {} 包裹着
凡是没有被{}包裹的, 就是pattern, 或者说pattern不能被{}包裹着.

一. 正则表达式做为 pattern

最常见的, 就是一个正则表达式做为一个 pattern了, 如:

awk '/555-5553/ { print $0 }' myfile

/555-5553/ 就是一个正则表达式, 如果输入记录匹配555-5553, 就输出这条记录, 这里只有第一行匹配 555-5553, 所以就输出了第一行这条记录. 

$ awk '/555-5553/ { print $0 }' myfile
Amelia 555-5553 amelia.zodiacusque@gmail.com F

二. 比较表达式做为 pattern

$ awk '$NF == "A" { print $0 }' myfile
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A

最后一个字段为 "A" 的, 输出这条记录.

$ awk '$NF != "A" { print $0 }' myfile
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R

最后一个字段不为 "A" 的, 输出这条记录.

三. 常量表达式做为 pattern

这种pattern一般是最不易被新手理解的, 事实上, 既然是 pattern 匹配, 结果就只有两种情况, 要么匹配(即为真),就执行后面的 action, 要么不匹配(即为假), 就不会执行后面的action.
所以, awk 的规则基本上也就是:

awk ' 真 { 执行代码 }; 假 { 不执行代码 }'

也理解为:

awk ' 条件 { 动作 } 条件 { 动作 } '

什么东西可以做为一个常量? 一个数字, 或者一个字符串, 都可以做为一个常量 pattern. 那这里就有一个规定了:

凡是非0的数字, 就表示pattern匹配成功, 也就是pattern为真. 否则表示匹配失败, 为假.
凡是非空的字符串, 就表示pattern匹配成功, 也就是pattern为真. 否则表示匹配失败, 为假.

注意: 字符串是由引号引起来的! 比如数字 0 与 字符串 "0" 不是一样的. 数字0为假, 字符串"0"为真(不为空).

如:

$ awk '1 { print $0 }' myfile
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R
$ awk '2 { print $0 }' myfile
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R
$ awk '0 { print $0 }' myfile
// 数字 0 做为 pattern, 0为假, pattern 匹配失败, 所以不执行 print $0, 没有打印.

  

$ awk ' "0" { print $0 }' myfile
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R
// 字符串 "0" 做为 pattern, 为真, pattern 匹配成功, 所以执行 print $0, 打印.

还有一些, 可能是写错的赋值语句做为了pattern的, 或者其他乱七八糟的, 等等..:

$ awk 'a=0'  myfile // 数字0. 假, 没输出.
$ awk 'a=1'  myfile // 1 为真.
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R
$ awk 'x-1'  myfile // x 为未定义的变量, 做数学运算, 结果为 -1 , 因 -1 也是非0的数字常量, pattern 匹配成功, 为真, print $0.
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R

  

$ awk 'xxoo'  myfile //xxoo为变量, 未赋值, 为假

  

$ awk '"xxoo"'  myfile // 字符串, 真.
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R

  

四. 空 pattern

$ awk '{print $0}' myfile
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R

// 这里没有 pattern, 空的, empty pattern, 那么就表示匹配输入记录永远成功, 也就是说永远为真, 这是龟腚. action永远都会执行.

我们知道, awk 的rule 就是由一系列 pattern 和 action 构成, 这里所谓的空 pattern, 也可以说是省略了 pattern, 那么 action 可不可以省略呢?
事实上, action也是可以省略的, 但如果省略了的话,它就会有一个默认的action行为, 即 { print $0 } !
很多人新手经常搞不懂一下的代码:

awk '{a=1}1' myfile

经常会碰到有人问, 这个代码后面的1是干嘛的? 其实, 我们拆分下 awk 的 rule 就明白了.
awk '{a=1}1' 这个语句包含了两条规则:

awk '
        [空pattern] {a=1}    #第一条规则
        1 [{省略的action}]   #第二条规则
'

第一条rule: {a=1} , 这条规则这里有一个{}大括号包裹着, 表示这是一个 action, 但是省略了pattern, 即空pattern, 
上面说了, 空pattern是永远匹配为真的, 
所以{a=1}这个action会针对每条输入记录对执行,只是我们看不到它的具体表现而已.

第二条rule: 1, 这条规则仅仅只有一个1字, 没有被{}大括号包裹着, 
所以这个1是一个pattern, 省略了{action}, 而这个数字 1 , 实际上就是一个常量表达式pattern, 因它为非0的数字,所以pattern匹配成功,为真,就执行action,
因为这里省略了{action},就触发默认的行为,而默认的action行为是print $0,即打印这条记录.

再如: awk '1;1' ,省略了两个action, 所以这条实际上就是两个 {print $0}{print $0}.

所以, 凡是action只是要输出这条记录的, 通通都可以省略这个 action.

如:

$ awk '/Amelia/ || /Martin/'  myfile
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Martin 555-6480 martin.codicibus@hotmail.com A
$ awk '$NF ~ /F/' myfile
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
$ awk 'NR==5' myfile
Broderick 555-0542 broderick.aliquotiens@yahoo.com R

  

五. 特殊的 pattern: BEGIN, END ..

在 awk 中, 肯定会经常看到 BEGIN, END 这两个玩意儿. 如 awk 'BEGIN { ... } END { ... } '

实际上, BEGIN 和 END 只是两个特殊的 pattern . 类似的还有 BEGINFILE,  ENDFILE.

BEGIN 在读入文件之前匹配成功, 即为在读入文件之前这条 rule 就已经执行了.
END 在处理完文件之后才匹配陈宫, 即在处理完文件之后才会执行这条 rule.

$ awk 'BEGIN { n=5 } NR==n { print $0 } END { print $0 }' myfile
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R

分析下这条 awk 语句:
首先, 它包含三条规则
1. BEGIN { n=5 }  ,BEGIN 为 特殊pattern, {n=5} 为 action
2. NR==n { print $0 }, NR==n 是一个比较表达式pattern, { print $0 } 为action.
3. END { print $0 }, END 也是一个特殊的pattern.

BEGIN 模式一般读入文件之前常用的是做一些相关的定义操作, 这里设定变量n=5. 
然后awk开始处理记录, 当 NR==n 时, 即处理到我们定义的那条记录时(第5条记录时), 执行 print $0, 输出这条记录.
最后是END模式, awk处理完文件里, END模式匹配成功,执行print $0, 即输出最后一条记录.
所以, 结果是输出第5条记录和最后一条记录.

六. 模式范围: begpat, endpat

这个模式范围, 是由两个 pattern 组成, 每个 pattern可以是任意的非特殊类型(非BEGIN/END模式类型)的pattern类型(可以是正则,比较,常量等pattern).
这个模式范围匹配的规则有点儿特殊, 这里以一个"开闸放水"的例子做为一个类比.
1. 首先以第一个pattern匹配输入记录, 如果第一个pattern匹配成功,就"打开放水的开关开始放水",[开关的状态: 开], 即会立即执行后面的action.此时不管第二个pattern是否匹配.
2. 接着再匹配第二pattern, 如果第二pattern匹配失败,开关的状态不变,即还是会执行action.
3. 接着继续以第二个pattern匹配下一条输入记录,直到第二个pattern匹配成功. 就"关闭放水的开关停止放水",[开关的状态: 关], 模式范围匹配结束.
4. 以1,2,3步骤进入下一轮模式范围匹配

如:

$ awk 'NR==4, /555-3430/ { print $0}' myfile
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A

先执行 NR==4 这个 pattern 匹配, 当第四条记录匹配成功时, 放水开关打开, 开始放水了, 即开始执行action , 执行 print $0 , 输出第四条记录.
接着使用 /555-3430/ 当前记录, 不成功.
第5条记录继续执行 action.继续以第二个pattern匹配这条记录..不成功..,开关是开的
第6条记录继续执行 action.继续以第二个pattern匹配这条记录..不成功..,开关是开的
...
..
直到匹配 /555-3430/, 第二个pattern匹配成功. 开关关闭. 模式范围匹配结束..
开始下一轮模式范围匹配..

以上就是各种 pattern 的简要解说了.. 至于 action, 也没啥可说的, action一般做具体的事情.
那些个流程控制语句 if/for/while 等一般都属于action了, 不能做为 pattern了.

来源:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=4246512&highlight=%B9%D8%D3%DA%2Bawk%2B%B5%C4%2Bpattern%28%C4%A3%CA%BD%29

附awk13问:http://bbs.chinaunix.net/thread-1790335-1-1.html

最新文章

  1. Vs2012编写C语言
  2. Font Awesome图标库
  3. map的用法
  4. css大牛的博客
  5. 能产生粒子效果的CAEmitterLayer
  6. POJ 2396 Budget【网络流】
  7. wpa_supplicant安装
  8. Hibernate逍遥游记-第10章 映射继承关系-002继承关系树中的根类对应一个表(discriminator、subclass)
  9. mysql utf8 中文
  10. gets和fgets函数的区别
  11. android CircularSeekBar
  12. ORA-16047: DGID mismatch between destination setting and target database
  13. android ListView隐藏FooterView(headerView)
  14. JQuery EasyUI DataGrid 获取属性值
  15. Windows程序设计学习笔记(四)自绘控件与贴图的实现
  16. Web App架构
  17. 第一个SpringBoot应用
  18. Linux自制编译内核
  19. 【安全开发】Android安全编码规范
  20. git clone直接提交用户名和密码

热门文章

  1. python 虚拟环境--virtualenv
  2. React Router 使用教程
  3. 51nod 1575 Gcd and Lcm
  4. Codeforces 626E Simple Skewness(暴力枚举+二分)
  5. HDU1016(素数环)
  6. c++只能编译无法运行或许缺少命令
  7. [国嵌笔记][030][U-Boot工作流程分析]
  8. IO代码记忆
  9. 怎么在谷歌浏览器中安装.crx扩展名的离线Chrome插件?
  10. PHP flock() 函数