awk:计算一列中字符串的出现次数,该列位于从模式 1 以下 2 行开始并以条件结束的一系列行之间

awk:计算一列中字符串的出现次数,该列位于从模式 1 以下 2 行开始并以条件结束的一系列行之间

我有一个包含数千行的输入文件。我对其中的一个部分感兴趣,其中包含文件中模式 /mo/ 的第一个实例。我需要搜索此模式,运行我的代码,然后在 mo 或其他行的任何其他模式之前停止代码。

它看起来像这样:

 >>>>>          -0.2834320000         -0.9672660000          0.0000000000  6.0 C
 m.o. irrep     orbital         orbital       orbital
              energy (a.u.)   energy (e.v.)   occupancy
========================================================
  1     1    -20.63710689       -561.5697        2.0000
  2     1    -20.58909944       -560.2634        2.0000
  3     1    -11.45645851       -311.7491        2.0000
  4     1    -11.29965696       -307.4823        2.0000
  5     1    -11.29203148       -307.2748        2.0000
  6     1     -1.44555716        -39.3360        2.0000
  7     1     -1.35738379        -36.9367        2.0000
  8     1     -1.07586111        -29.2760        2.0000
  9     1     -0.91591305        -24.9235        2.0000
 10     1     -0.75492584        -20.5428        2.0000
 11     1     -0.71126523        -19.3547        2.0000
 12     1     -0.70828880        -19.2737        2.0000
 13     2     -0.62802299        -17.0895        2.0000
 14     1     -0.61775719        -16.8102        2.0000
 15     2     -0.50208166        -13.6625        2.0000
 16     1     -0.49193707        -13.3864        2.0000
 17     1     -0.43731872        -11.9002        2.0000
 18     2     -0.43546575        -11.8497        2.0000
 19     2      0.07335689          1.9962        0.0000

目标

  1. 从模式 /mo/ 下面的 3 行开始(其中 $1=1)。
  2. 计算$2不等于“1”的次数(在其他文件中,$2也可以是3或4,所以我需要按$2!= 1来数)。
  3. 该计数必须在 $3 为负数的行范围内,即。直到从底部数第二行。

无法使用模式 /====/,因为它出现在文档的前面。

  • 输出应为 3。在 $3 为负数的行范围内,有 3 行 $2 不等于 1。

试图

我在网上搜索了其他答案,这些答案为我提供了要使用的部分代码。例子:

  • 将我的起始线定义为模式加 3 (来源):

    awk '/m.o./{n=NR+3}n
    
  • 在起始行和最后一行之间,计算有多少次 $2 != "1" (来源

    awk '$2!="1"{++count}
    
  • 定义我的最后一行如下:

    awk '{if ($3 > 0){print count; exit}
    

但我不知道如何将所有这些放在一起。重要的是,我必须以某种方式避免将额外的 2 计算在底线的 2 美元中。

我当然愿意重写上面的代码。我只是想提供一些例子以便清楚起见。

谢谢。

答案1

哇我终于用下面的行弄清楚了:

 awk '$1 ~ /m.o./ { n=NR+3}n && $3+0 > 0 { n=0 } {if ( n != 0 && $2 != "1" && $3+0 < 0) { count++; }} END { print count }' input

之前的问题是每个语句似乎都独立地作用于整个文档,因此我无法强制条件仅在一定范围内起作用,这导致它计算了许多我不希望的其他行算了。我不断得到大于正确答案 3 的值。

例如,使用标志——这似乎是网络上解决此问题的常见解决方案——标志似乎没有在适当的行激活,或者计数发生在标志允许的行范围之外。它正在计算甚至不属于我的模式的行。 Inian 编码以排除具有 >>>> 模式的行(无论出于何种原因返回计数匹配),但还有其他模式不匹配,并且在文档中找到所有 20k 行的模式是不合理的。

这最终对我有用。

 $1 ~ /m.o./ { n=NR+3}n

这将脚本设置为从 $1 包含“mo”的第一个实例开始。我需要指定 $1 以避免脚本中第二次出现 mo 模式。幸运的是,第二个实例在 $2 中,所以我通过仅匹配 $1 来避免它。如果两者都在同一列中,我不知道如何避免它。

在匹配点,n 被定义为行号 (NR) 加括号中的 3,然后通过在括号外再次添加它来记录。通过这种方式,我似乎能够使用 awk 从一个模式加上任意数量的行开始。

  && $3+0 > 0 {n=0}

这允许我根据可变条件结束行范围,而不是匹配模式(网络上的许多其他解决方案使用 /pattern/ 匹配定义的字符串模式来定义行范围的末尾,我无法弄清楚如何适应这里)。

我相信 && 会维护之前的模式匹配以绑定起点,然后对于文档中之后的任何点,其中 $3 > 0(我的条件),n 变为零。

最后,我有办法绑定起始线和结束线。

我现在可以在该范围内应用我想要的函数,即根据条件计算行数。

   {if ( n != 0 && $2 != "1" && $3+0 < 0) { count++; }}

我通过调用第一项来保持在我的行范围内:如果 n 不为零,这只是我的模式匹配和我设置的条件之间的情况。在此行范围内,脚本会提取 $2 不为 1 并且 $3 为负数的行。它为每个实例将我的计数变量增加 1。

   END { print count }' input

在脚本的末尾,它打印输入文件的变量计数总和。

答案2

有很多方法可以做到这一点,但最简单易懂的方法可能如下:

您可以创建一个复杂的条件来选择要计数的行:

awk 'BEGIN { total=0 } NR > 3 && $2 != 1 && $3 < 0  { total++ } END { print total }' 

或者您可以将条件放在代码块中:

awk 'BEGIN { total=0 } NR > 3 { if ( $2 != 1 && $3 < 0 ) { total++ } } END { print total }' 

答案3

你可以试试这个 awk :

awk '$1=="m.o."{if(l){exit};l++;next}l&&l<3{l++;next}l{if($3<0&&$2!=1)c++}END{print c}' infile

相关内容