【问题标题】:AWK - Search for a pattern-add it as a variable-search for next line that isn't a variable & print it + variableAWK - 搜索模式 - 将其添加为变量 - 搜索不是变量的下一行并打印它+变量
【发布时间】:2015-06-14 02:33:49
【问题描述】:

我有一个给定的文件:

application_1.pp

application_2.pp

    #application_2_version => '1.0.0.1-r1',
    application_2_version => '1.0.0.2-r3',

application_3.pp

    #application_3_version => '2.0.0.1-r4',
    application_3_version => '2.0.0.2-r7',

application_4.pp

application_5.pp

    #application_5_version => '3.0.0.1-r8',
    application_5_version => '3.0.0.2-r9',

我希望能够读取此文件并搜索字符串

".pp"

找到该字符串后,它将该行添加到变量中并存储。 然后它读取文件的下一行。如果遇到前面有 # 的行,它会忽略它并移至下一行。

如果遇到不包含“.pp”且不以 # 开头的行,则应在新文件中最后存储的变量旁边打印出该行。

输出如下所示:

application_1.pp
application_2.pp    application_2_version => '1.0.0.2-r3',  
application_3.pp    application_3_version => '2.0.0.2-r7',
application_4.pp
application_5.pp    application_5_version => '3.0.0.2-r9',

我想用 awk 来实现。如果有人知道如何做到这一点并且这是一个简单的解决方案,如果他们可以与我分享,我会很高兴。如果它更复杂,那么了解 awk 中我需要了解哪些内容以了解如何执行此操作(数组、变量等)会很有帮助。甚至可以用 awk 实现还是需要其他工具?

谢谢,

【问题讨论】:

    标签: regex linux awk sed gawk


    【解决方案1】:

    我会说

    awk '/\.pp/ { if(NR != 1) print line; line = $0; next } NF != 0 && substr($1, 1, 1) != "#" { line = line $0 } END { print line }' filename
    

    它的工作原理如下:

    /\.pp/ {                                # if a line contains ".pp"
      if(NR != 1) {                         # unless we just started
        print line                          # print the last assembled line
      }
      line = $0                             # and remember this new one
      next                                  # and we're done here.
    }
    
    NF != 0 && substr($1, 1, 1) != "#" {    # otherwise, unless the line is empty
                                            # or a comment
      line = line $0                        # append it to the line we're building
    }
    
    END {                                   # in the end,
      print line                            # print the last line.
    }
    

    【讨论】:

    • 这个程序很好地解决了这个任务。感谢您的时间和解释。
    【解决方案2】:

    你可以使用 sed:

    #n
    /\.pp/{
        h
        :loop
        n
        /[^#]application.*version/{
            H
            g
            s/\n[[:space:]]*/\t/
            p
            b
        }
        /\.pp/{
            x
            p
        }
        b loop
    }
    

    如果你把它保存为 s.sed 并运行

    sed -f s.sed file
    

    你会得到这个输出

    application_1.pp
    application_2.pp    application_2_version => '1.0.0.2-r3',
    application_3.pp    application_3_version => '2.0.0.2-r7',
    application_4.pp
    application_5.pp    application_5_version => '3.0.0.2-r9',
    

    说明

    #n 抑制正常输出。

    一旦我们匹配到/\.pp/,我们将该行存储到h 的保持空间中,并启动loop

    我们用n转到下一行

    如果它匹配/[^#]application.*version/,意味着它不是以#开头,那么我们将该行附加到带有H的保持空间,然后将保持空间复制到带有g的模式空间,并将换行符和任何后续空格替换为制表符。最后我们用p打印,用b跳到脚本结尾

    如果匹配/\.pp/,那么我们用x交换模式和保持空格,用p打印。

    【讨论】:

    • 感谢您对这个问题的贡献!我尝试了您的解决方案,它适用于我提供的文件。但是,当我尝试将其应用于模式略有不同的文件时,它不起作用。我希望它与正则表达式模式有关:/[^#]application.*version/ 如果我想应用相同的过程,但这次文件名不是连续的:application_1.pp \ application_2.pp 等等。而是ab.pp cd.pp ef.pp 和它们后面的行开始cd_version => '1.0.0.2-r3', \ ef_version => '1.0.0.2-r3', 还能用不同的正则表达式实现吗?
    • 如果是这样,我会阅读正则表达式并使用它,直到它起作用为止。但如果它是 sed 的限制,那么 awk 提供的其他解决方案更合适。
    • 是的,也可以这样做,只需更改正则表达式即可。
    猜你喜欢
    • 2019-03-18
    • 1970-01-01
    • 2016-07-28
    • 1970-01-01
    • 2013-05-03
    • 1970-01-01
    • 1970-01-01
    • 2015-10-17
    • 2012-12-10
    相关资源
    最近更新 更多