我正在尝试编写一个 .awk 源文件来过滤 .txt,我想知道如何在第二个命令中使用 max 变量
BEGIN {max1=0}
找到两个模式(0 和 1)之间 $4 的最大值并将其设置为变量
{if ($4>0 && $4<1)
max1=$4
else if ($4==1)
max=max1}
END {print max}
/Nodes/ {f=1} /EndNodes/ {f=0} #Gives lines after Nodes and before EndNodes
{if ($2+0>=0 && $3+0==0 && max==$4) #Filters the given lines between Nodes and EndNodes
{print $1}}
我的猜测是,我需要在定义 max 变量后从头开始运行程序(因为它使用与第二个命令相同的行。
期望输出应该是:20、31和32
输入
$Nodes
34
1 0.0000000E+000 0.0000000E+000 0.0000000E+000
2 6.0000000E-003 0.0000000E+000 0.0000000E+000
3 0.0000000E+000 6.0000000E-003 0.0000000E+000
4 -6.0000000E-003 0.0000000E+000 0.0000000E+000
5 0.0000000E+000 -6.0000000E-003 0.0000000E+000
6 2.1213203E-003 2.1213203E-003 0.0000000E+000
7 -2.1213203E-003 2.1213203E-003 0.0000000E+000
8 -2.1213203E-003 -2.1213203E-003 0.0000000E+000
9 2.1213203E-003 -2.1213203E-003 0.0000000E+000
10 4.2426407E-003 4.2426407E-003 0.0000000E+000
11 -4.2426407E-003 4.2426407E-003 0.0000000E+000
12 -4.2426407E-003 -4.2426407E-003 0.0000000E+000
13 4.2426407E-003 -4.2426407E-003 0.0000000E+000
14 2.1213203E-003 0.0000000E+000 0.0000000E+000
15 0.0000000E+000 2.1213203E-003 0.0000000E+000
16 -2.1213203E-003 0.0000000E+000 0.0000000E+000
17 0.0000000E+000 -2.1213203E-003 0.0000000E+000
18 0.0000000E+000 2.1213203E-003 6.0000000E-003
19 0.0000000E+000 6.0000000E-003 6.0000000E-003
20 0.0000000E+000 0.0000000E+000 6.0000000E-003
21 -4.2426407E-003 4.2426407E-003 6.0000000E-003
22 -2.1213203E-003 2.1213203E-003 6.0000000E-003
23 -6.0000000E-003 0.0000000E+000 6.0000000E-003
24 -2.1213203E-003 0.0000000E+000 6.0000000E-003
25 -4.2426407E-003 -4.2426407E-003 6.0000000E-003
26 -2.1213203E-003 -2.1213203E-003 6.0000000E-003
27 0.0000000E+000 -6.0000000E-003 6.0000000E-003
28 0.0000000E+000 -2.1213203E-003 6.0000000E-003
29 4.2426407E-003 -4.2426407E-003 6.0000000E-003
30 2.1213203E-003 -2.1213203E-003 6.0000000E-003
31 6.0000000E-003 0.0000000E+000 6.0000000E-003
32 2.1213203E-003 0.0000000E+000 6.0000000E-003
33 4.2426407E-003 4.2426407E-003 6.0000000E-003
34 2.1213203E-003 2.1213203E-003 6.0000000E-003
$EndNodes
$Elements
#And some more data
$EndElements
答案1
这是一个一次性解决方案:
/Nodes/ { read = 1 }
/EndNodes/ { read = 0 }
!read { next }
NF == 4 { n = $1; x = $2; y = $3; z = $4 }
z > max { delete set; i = 1; max = z }
x >= 0 && y == 0 && z == max { set[i++] = n }
END { for (i in set) { print set[i] } }
该read
变量决定我们是否应该对当前记录执行操作。如果是 1,那么我们就这样做。
如果我们对当前输入不感兴趣,则第三个块会丢弃当前输入,并从顶部继续处理下一条记录。
第 4个块设置了四个便利变量 、n
、x
和y
。它们比其他的z
更容易阅读。$1
第 5 个块删除数组set
。该set
数组是我们迄今为止找到的并且满足条件的所有节点号的集合。由于如果我们找到 的新最大值z
,则会执行此块,因此所有先前找到的节点都会失效。我们还保存新的最大值 ( max
)。该变量i
只是数组的索引(基本上是一个计数器)。如果尚未找到最大值,则max
在测试中未初始化的将被视为零。
当我们找到满足条件的节点时,将执行第 6 个块。节点号保存在set
数组中并i
递增。
最后,我们循环遍历set
数组并输出其内容。
在GNU下运行的结果awk
是
20
31
32
BSDawk
和mawk
在 OpenBSD 上运行以相反的顺序生成列表。
答案2
awk解决方案:
get_max_nodes.awk脚本:
#!/bin/awk -f
BEGIN{ max=0 }
NR==FNR{ # processing the 1st input file
if ($4~/^[0-9]/) { # if the 4th field is a number
if($4+0 > max) max=$4+0 # capturing maximal number
}
next
}
{ # processing the 2nd input file (same file)
if ($4~/^[0-9]/ && $2+0>=0 && $3+0==0 && $4+0==max) {
print $1
}
}
用法:
awk -f get_max_nodes.awk input.txt input.txt
输出:
20
31
32
答案3
我没有足够的声誉来发表评论,所以我被迫回答。我的第一条评论是 awk 不是进行实数数学的最佳工具。它更擅长字符串和整数。
awk 的其他要点: BEGIN 段落发生在从输入中读取任何行之前。 END 段落发生在所有行都被读取之后。
注意:awk 不会保存或关心除当前输入行/记录之外的任何内容,除非您采取措施在代码中存储记录/字段。这需要在 BEGIN 和 END 之间发生。
这些段落之间的代码仅设置/重置变量,但不对它们的值执行任何操作。本质上,您可以尾部 -1 输入文件并通过管道将输出进行剪切,以获得类似的结果。
看来您的意图是测试第 4 列中的数字以找到 max 或 max1,并且如果第 4 列包含此 max,则仅打印第 1 列,然后成功测试第 2 列和第 3 列。此逻辑需要移到 END 之前除非您只关心文件的最后一行。
请记住,在 awk 中,每一行输入(默认情况下)都会与每个条件进行比较。如果条件为真,则执行该操作或操作列表。同一行上很可能有多个条件触发操作。
我的第一印象是您需要重新评估您的流程。确定重要性顺序并采取相应的行动。例如,对我来说,第一重要顺序仅作用于输入文件中两个标志之间的数据。接下来,确定 4 个字段中每个字段中的实数是否可以转换为(或视为)整数(或字符串)而不丢失其含义。实际数据本身不需要更改,只需更改其在代码中的表示即可。这些可以再次转换回来,但失去原始数字准确性的可能性很高。最后,选择是否需要存储所有/任何未排序的随机数据以供以后处理,或者立即提供每行输出。
下面的元示例可以更有效地完成......以一个标志开始,让您知道是否是时候开始解析。你见过 $0 ~= /Nodes/ 行吗?开始=0。您可能还想通过测试 $0 ~= /EndNodes/ line, stop=0 来准备了解何时停止解析数据。如果您要存储数据,您可能需要一个计数器,count=0。
BEGIN {
start=0
stop=0
count=0
max=0
}
/EndNodes/ {
stop=1
}
/Nodes/ {
start=1
}
NF==4 {
if (start==1 && stop==0) {
count++
column1[count]=$1
column2[count]=substr($2,1,index($2,".")-1)
column3[count]=substr($3,1,index($3,".")-1)
column4[count]=substr($4,1,index($4,".")-1)
}
}
# Now print column1 if column2 is non-negative and column3=0 and column4=max
# In the first loop through the array/list, find max
END {
for (loop=1;loop<=count;loop++) {
if (column4[loop]>max) {
max=column4[loop]
}
}
for (loop=1;loop<=count;loop++) {
if (column4[loop]==max && column3[loop]==0 && column2[loop]>=0) {
print column1[loop]
}
}
}
如所写,输出将是
20
31
32