根据列模式解析文本文件

根据列模式解析文本文件

我想知道是否有一种简单的方法可以使用 awk 或任何其他命令来解析文本文件,例如类似以下的文件:

Step Temp Enthalpy
0    0    -368
100  1    -369
200  2    -372
300  6    -362
400  9    -365
SHAKE stats (type/ave/delta) on step 500
1 1.09  8.71362e-08
500  13   -358
600  15   -339
.
.
900  25   -306
SHAKE stats (type/ave/delta) on step 1000
1 1.09 7.06858e-08
1000 28  -306
.
.
.

可以仅打印我想要的特定数字列的输出,例如仅温度值。我知道我可以awk '{print $2}'对温度值执行类似操作,但是我的特定数据文件在“步骤温度焓”表之前和之后还有其他行各种数据,这使得这不切实际,所以我希望理想情况下删掉此“步骤温度焓”信息之前和之后的所有内容,并仅打印出我需要的数据文件此部分的特定列。数据文件每 5 步还有一行“SHAKE stats”,以及我想删除的行“1 1.09 ....etc”。如果我只打印温度列,我希望它输出:

0
1
2
6
9
13
15
.
.
25
28

答案1

您拥有的简单模式是取出包含数字/以数字开头的行中的第 2 列。awk命令的通常结构是/Pattern in current line/ { commands};。仅当在当前行中找到模式时,才会执行括号中的命令。因此我们可以这样做:

$ awk '/^[[:digit:]]/{print $2}' input.txt
0
1
2
6
9
1.09
13
15
25
1.09
28

要删除浮点数,请使用逻辑 AND 运算符添加额外的模式&&

$ awk '/^[[:digit:]]/ && $0 !~ /[.]/ {print $2}' input.txt
0
1
2
6
9
13
15
25
28

或者,只需使用否定模式来排除抖动统计数据:

awk '!/^SHAKE/ && $0 !~ /[.]/ {print $2}' input.txt 

为了解决评论中的问题,您可以将范围模式(类似于/Pattern1/,/Pattern2/ {commands})与 if 语句结合起来。范围模式将仅对符合范围的行执行花括号内的命令,然后 if 语句可以进行额外的过滤。在这种特殊情况下,您可以简单地将其与之前的解决方案结合起来,如下所示:

$ awk '$0 == "Step Temp Enthalpy",0 { if( $0 ~ /^[[:digit:]]/ && $0 !~ /[.]/  ) print $2  }' input.txt

该模式$0 == "Step Temp Enthalpy",0表示处理精确 Step Temp Enthalpy到行0,即文件末尾。

答案2

这是一种基于数据结构而不是匹配内容的(可能)更简单的方法:

  • 使用模数运算来测试我们是否在其中一条SHAKE stats线上
  • 如果是这样,那就把下一行吞下去getline,继续前进
  • 否则,打印第二个字段

所以

$ awk '!(NR%7) {getline; next} {print $2}' data
Temp
0
1
2
6
9
13
15


25
28

相关内容