awk next 和模式匹配
Posted
技术标签:
【中文标题】awk next 和模式匹配【英文标题】:awk next and pattern match 【发布时间】:2015-03-19 00:19:55 【问题描述】:如果我们有以下csv文件,我们只想得到“DELTA Energy Terns”部分中的$9,不包括以“Frame”开头的行
Ligand Energy Terms
Frame #,VDWAALS,EEL,EGB,ESURF,ESCF,G gas,G solv,TOTAL
0,0.0,0.0,-37.2465,2.70257904,98.8916,0.0,-34.54392096,64.34767904
1,0.0,0.0,-33.1958,2.71419624,80.6403,0.0,-30.48160376,50.15869624
DELTA Energy Terms
Frame #,VDWAALS,EEL,EGB,ESURF,ESCF,DELTA G gas,DELTA G solv,DELTA TOTAL
0,-43.3713,0.0,44.4036,-5.24443392,-27.4605,-43.3713,39.15916608,-31.67263392
1,-43.7597,0.0,37.343,-5.1764544,-23.3471,-43.7597,32.1665456,-34.9402544
2,-42.5618,0.0,44.0748,-5.2738956,-26.6719,-42.5618,38.8009044,-30.4327956
3,-43.1034,0.0,41.3681,-5.25029544,-27.1501,-43.1034,36.11780456,-34.13569544
期望的输出:
-31.6726
-34.9402
-30.4327
-34.1356
以下尝试将打印出所有 9 美元,包括“配体能量条款”部分中的 9 美元。
awk -F, '$1 ~ /DELTA Energy Terms/ next $1 ~ /Frame/ next printf("%24.4f\n",$9)'
awk -F, '$1 ~ /DELTA Energy Terms/ next printf("%24.4f\n",$9)'
有哪位大师能开导吗?
【问题讨论】:
【参考方案1】:以下应该可以解决问题
awk -F, '/^DELTA/ capture=1 /Energy Terms$/ next /^Frame/ next (capture) print $9'
我使用capture
标志来控制是否应捕获单个记录。默认情况下,capture
为零。当DELTA Energy Terms
行被解析时,我开始捕获。我跳过任何以Energy Terms
结尾或以Frame
开头的行。否则,如果我们在“捕获”,那么我就带出第九个元素。
如果您经常使用此脚本,我建议您使用类似于以下脚本的内容:
#!/usr/bin/awk -f
BEGIN
FS = ","
/^DELTA Energy Terms/
capture = 1;
next
/Energy Terms$/
capture = 0;
next
/^Frame/ next
(capture) print $9
将脚本保存为extract-delta
并使其可执行,然后您可以像使用任何其他shell 命令一样使用它:
$ cat input-file | tr -d '\015' | ./extract-delta
-31.67263392
-34.9402544
-30.4327956
-34.13569544
【讨论】:
这个工作几乎完美!如果我们执行 "awk -F, '/^DELTA/ capture=1 /Energy Terms$/ next /^Frame/ next (capture) print $9' input > check.dat" 将会有每行末尾的尾随 (^M)。我可以知道这背后的任何原因吗? 这通常是由 DOS 风格的行尾字符 (\r\n
) 引起的。 \r
转换为 Ctrl+M,\n
转换为 Ctrl+J。您可以通过tr -d '\015'
过滤输入以去除回车字符。
谢谢!我可以知道是否有“捕获”的任何 awk 手册?搜索后我找不到任何东西。它看起来很强大,很想深入研究它。
capture
只是一个变量,它为输入的一部分启用print $9
操作。
嗨 D. Shawley,我可以知道为什么括号 capture=1 和 (capture) 不同吗?这种“捕获标志”技术有什么术语吗?【参考方案2】:
您也可以使用 bash 完成此操作,使用以下方法:
tail -n +$((2 + $(grep -n "DELTA Energy Terms" input.txt | cut -d":" -f1) )) input.txt | cut -d"," -f9
tail -n +$((2 + $(grep -n "DELTA Energy Terms" input.txt
部分将打印输入文件的行,从包含 DELTA 能量项 加 2 的行开始,然后cut
将为您提供您正在查找的第 9 个字段为了。
【讨论】:
【参考方案3】:你可以试试下面的 awk 命令。
$ awk -v RS="\n\n" -v FS="\n" '/^DELTA Energy Terms/for(i=3;i<=NF;i++)split($i, a, /,/);print a[9]' RS= file
-31.67263392
-34.9402544
-30.4327956
-34.13569544
RS="\n\n"
,所以一个空行设置为记录分隔符。
FS="\n"
,换行符设置为字段分隔符。
/^DELTA Energy Terms/
如果记录以^DELTA Energy Terms
开头,则对该特定记录执行以下操作。
for(i=3;i<=NF;i++)split($i, a, /,/);print a[9]
遍历除 1 和 2 之外的所有字段,然后根据逗号拆分每个字段,然后将吐出的项目存储到名为 a
的数组中。
print a[9]
打印关联数组 a
中第 9 个索引处的元素。
【讨论】:
【参考方案4】:所有这些解决方案都有效,因此解决了眼前的问题,但没有一个回答隐含的问题。
要查看有问题的命令,为什么这不起作用?
'$1 ~ /DELTA Energy Terms/ next $1 ~ /Frame/ next printf("%24.4f\n",$9)
让我们分解一下。
# Skip every line where the first field matches.
$1 ~ /DELTA Energy Terms/ next
# No line matches this criteria, so this has no effect.
# Explanation: The field separator isn't set, so defaults to breaking fields on white space.
# If you print out the first field, you will see "DELTA" on this line, not "DELTA Energy Terms".
# Skip every line where the first field matches "Frame".
$1 ~ /Frame/ next
# This matches and gets skipped.
# Print every line that didn't get skipped.
printf("%24.4f\n",$9)
# The two "Energy Terms" title lines don't have any entries in field 9,
# so it prints blanks for those lines.
【讨论】:
以上是关于awk next 和模式匹配的主要内容,如果未能解决你的问题,请参考以下文章