zoukankan      html  css  js  c++  java
  • awk 的 pattern(模式)

    我们知道, 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

    "世界上只有一种真正的英雄主义,就是认清了生活的真相后,还依然执着地热爱它。" ——罗曼·罗兰
  • 相关阅读:
    1094. Car Pooling
    121. Best Time to Buy and Sell Stock
    58. Length of Last Word
    510. Inorder Successor in BST II
    198. House Robber
    57. Insert Interval
    15. 3Sum java solutions
    79. Word Search java solutions
    80. Remove Duplicates from Sorted Array II java solutions
    34. Search for a Range java solutions
  • 原文地址:https://www.cnblogs.com/irockcode/p/6670212.html
Copyright © 2011-2022 走看看