我想知道是否有一种简单的方法可以使用 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