【问题标题】:Print between patterns -awk在模式之间打印 -awk
【发布时间】:2016-01-04 21:39:14
【问题描述】:

我有以下输入文件

-------------------------------------
--- A-TKE spectrum (post-neutron)---
-------------------------------------

2-dim. array: (A =  73 To  162 Step 1) (E =  122 To  198 Step 1)

(The data are written according to the loop structure specified above.
The last loop is the inner-most one. Line breaks are not related to the data structure!

 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 1 0 0 2 0 0 1 0 0 0 0 


    </A_TKE>
  </Results>

这个文件是一个更大文件的一部分,它包含更多类似于上面的数字块。

我想要做的是在一个单独的文件中打印文件中的数字。作为第一次尝试,我想“让我们打印两个模式之间的内容”。 START 模式为 --- A-TKE spectrum (post-neutron)---,END 模式为 &lt;/A_TKE&gt;

我用过

awk '/--- A-TKE spectrum (post-neutron)---/{flag=1;next}/</A_TKE>/{flag=0}flag{print}' input

令我惊讶的是,屏幕上没有打印任何内容。知道为什么会这样吗?

如果我现在可以将next 替换为与给定模式后我要打印的行相对应的数字,我也想这样做。

【问题讨论】:

  • 那些看起来像XML 标签。是吗?
  • @Sobrique : 不 :) 它只是一个代码的输出文件,我想操纵它!
  • 您要打印哪些数字?请指定您期望的输出。
  • @skmrx : 我想打印大量的数字

标签: perl awk printing sed pattern-matching


【解决方案1】:

在 perl 中(因为当您以 awk 开头时,这也被标记为 perl):

perl -ne 'print if m/post-neutron/...m/A_TKE/' input

这会做你想做的事。

它通过使用range operator 工作 - 这是一个 perl 构造,用于测试当前文件是否在两个标记之间。

事实上perl 可以像awksed 一样内联运行。 -ne 表示“将此代码包装在一个 while 循环中”,一次迭代一行。 (例如 sed/awk/grep 默认执行)。

否则...这在一定程度上取决于您文件中的 else 内容。因为从您提供的示例中 - 唯一以数字开头的行是您想要的行。所以:

perl -ne 'print if m/^\s*\d+\s*\d+/'

(或者结合两个测试:

perl -ne 'print if m/post-neutron/...m/A_TKE/ and m/^\s*\d+\s*\d+/'

这将输出两个文本标记之间的任何内容,该标记在行首具有数字-空格-数字。

【讨论】:

    【解决方案2】:

    您的 awk 脚本就快到了。我会这样构建它:

    awk '
      /<\/A_TKE>/ {exit}
      flag && NF==50 {print} 
      /--- A-TKE spectrum .post-neutron.---/ {flag=1}
    ' input
    

    你当然可以优化它,但只要看看它的逻辑,你就不需要做进一步的处理,一旦你到达你的结束标记......你只想在你的开始标记之后开始打印。

    请注意,我已将开始标记中的括号替换为点,因为括号被解释为正则表达式的一部分。我相信您可能正在考虑搜索这些简单的字符串,但它们是正则表达式。

    【讨论】:

    • 感谢您的回答。问题是我附加的文件是包含&lt;A-TKE&gt; 的更大文件的一部分。所以区别就是这个斜​​线,所以我认为有必要
    • 我运行 awk ' ///A_TKE/{exit}flag{print} /--- A-TKE 频谱 .post-neutron.---/{flag=1}' 但我得到了{exit} 的语法错误
    • 啊,我当然不知道早期的标志。在您的评论中,您的 awk 脚本以 ///A_TKE/ 开头。不应该是/\/A_TKE/吗?反斜杠“转义”正斜杠,否则将被解释为正则表达式分隔符。另外,您正在运行什么操作系统和/或什么版本的 Awk?
    • 是的,你是对的。我正在运行Ubuntu 12.041 and my awk` 版本是3.1.8
    • @Thanos,我改进了结束标记检测并在脚本中的第二个表达式中添加了另一个条件。在此版本中,仅打印具有 50 个字段(由空格分隔)的行。另外,作为参考,您没有使用awk,您实际上使用的是gawk(GNU awk)。 Gawk 具有许多传统 awk 所缺少的额外功能(尽管我们不需要解决您的问题)。
    【解决方案3】:

    如果你想提取只有数字的行

     awk 'NF && !/[a-zA-Z\-]+/' input.file
    

    会生成

     0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 1 0 0 2 0 0 1 0 0 0 0
    

    使用模式和智能计数器,您可以将其编写为

    awk   '/\/A_TKE/{exit} 
           f&&s&&s--{next} 
               f&&NF{print} 
    /A-TKE spectrum/{f=1;s=7}' input.file
    

    根据需要微调模式。

    【讨论】:

    • 我在最初的问题中没有提到它,但这只是包含更多数字块的更大文件的一部分,因此我认为我必须坚持使用模式
    【解决方案4】:

    试试这个简单的sed 命令

    sed -n '/A-TKE/,/<\/A_TKE>/p' FileName
    

    【讨论】:

      【解决方案5】:

      一些工作思路

      Awk 可以使用这个简单的命令在两个匹配的行之间打印:

      awk '/PATTERN1/,/PATTERN2/' file.txt
      

      如果您想更好地控制找到行时发生的情况,可以使用标志方法。

      awk '/A-TKE/{f=1;for (i=0;i<7;i++){getline}}/A_TKE/{f=0}f' file.txt 
      

      调整i&lt;7 以指定要跳过的行数。

      此外,在这种特殊情况下,您可以利用您有 50 个数字字段的事实,这不太可能出现在文件的其他任何地方。因此,您还可以通过以下方式获取感兴趣的数字:

      awk 'NF>40' file.txt
      

      NF 是一个特殊的 awk 变量,用于存储当前记录(行)中的字段(列)数。

      为什么你的方法不起作用

      您的方法不起作用,因为 awk 中 // 之间的所有内容都被视为正则表达式。在您的情况下,您在字符串中有几个 -() 没有转义,因此假定它们的特殊含义,因此您键入的表达式永远不会匹配,因此标志永远不会设置为 1 并且 awk 不会打印一行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多