我是文本预处理和AWK语言的新手。
我试图遍历给定字段(field1)中的每条记录,找到值的最大值和最小值,并将其存储在变量中。
算法:
1)设置Min = 0和Max = 0
2)循环$ 1(字段1)
3)比较字段1的FNR并设置Max和Min
4)最后打印Max和Min
这是我试过的:
BEGIN{max = 0; min = 0; NF = 58}
{
for(i = 0; i < NF-57; i++)
{
for(j =0; j < NR; j++)
{
min = (min < $j) ? min : $j
max = (max > $j) ? max : $j
}
}
}
END{print max, min}
#Dataset
f1 f2 f3 f4 .... f58
0.3 3.3 0.5 3.6
0.9 4.7 2.5 1.6
0.2 2.7 6.3 9.3
0.5 3.6 0.9 2.7
0.7 1.6 8.9 4.7
此处,f1,f2,..,f58是数据集中的字段或列。
我需要遍历第一列(f1)并找到Min-Max。
需要输出: 最小= 0.2 最大= 0.9
我得到的结果是: Min =''(我没有得到任何结果) Max = 9.3(我得到所有字段的最大值而不是field1)
这是出于学习目的,所以我要求一列,以便我可以自己尝试多列
这就是我所拥有的:
这个for循环只循环4次,因为只有4个字段。 for循环中的代码是否会为每个记录执行5次?
for(i = 0; i < NF; i++)
{
if (min[i]=="") min[i]=$i
if (max[i]=="") max[i]=$i
if ($i<min[i]) min[i]=$i
if ($i>max[i]) max[i]=$i
}
END
{
OFS="\t";
print "min","max";
#If I am not wrong, I saved the data in an array and I guess this would be the right way to print all min and max?
for(i=0; i < NF; i++;)
{
print min[i], max[i]
}
}
答案 0 :(得分:4)
这是一个工作解决方案,它比你正在做的更容易:
/^-?[0-9]*(\.[0-9]*)?$/
检查$1
确实是有效数字,否则将被丢弃。
sort -n | awk '$1 ~ /^-?[0-9]*(\.[0-9]*)?$/ {a[c++]=$1} END {OFS="\t"; print "min","max";print a[0],a[c-1]}'
如果你不使用它,那么需要初始化min和max,例如使用第一个值:
awk '$1 ~ /^-?[0-9]*(\.[0-9]*)?$/ {if (min=="") min=$1; if (max=="") max=$1; if ($1<min) min=$1; if ($1>max) max=$1} END {OFS="\t"; print "min","max";print min, max}'
可读版本:
sort -n | awk '
$1 ~ /^-?[0-9]*(\.[0-9]*)?$/ {
a[c++]=$1
}
END {
OFS="\t"
print "min","max"
print a[0],a[c-1]
}'
和
awk '
$1 ~ /^-?[0-9]*(\.[0-9]*)?$/ {
if (min=="") min=$1
if (max=="") max=$1
if ($1<min) min=$1
if ($1>max) max=$1
}
END {
OFS="\t"
print "min","max"
print min, max
}'
在您的输入上,输出:
min max
0.2 0.9
编辑(回复评论,要求提供有关awk
工作原理的更多信息):
Awk循环遍历lines
(名为records
),并且每行都有可用的列(名为fields
)。每个awk
次迭代都会读取一行,并提供NR
和NF
个变量。在您的情况下,您只对第一列感兴趣,因此您只能使用$1
这是第一列field
。对于record
匹配$1
的每个/^-?[0-9]*(\.[0-9]*)?$/
,它是匹配正负整数或浮点数的正则表达式,我们要么将值存储在数组a
中(在第一个版本)或根据需要设置min
/ max
变量(在第二个版本中)。
以下是条件$1 ~ /^-?[0-9]*(\.[0-9]*)?$/
的解释:
$1 ~
表示我们正在检查第一个字段$1
是否与斜杠之间的正则表达式匹配^
表示我们从$1
字段-?
表示可选的minus sign
[0-9]*
是任意位数(包括零,因此.1
或-.1
可以匹配)()?
表示可以存在或不存在的可选块\.[0-9]*
如果存在可选块,则应该以{{1}}开头并包含零个或多个数字(因此dot
或-.
可以匹配!正确的,如果你有不确定的输入).
表示我们匹配到$
字段如果您想循环浏览$1
,则必须使用从fields
到1
(包含)的for循环,如下所示:
NF
(请注意,为了简单起见,我没有在这里检查输入)
哪个输出:
echo "1 2 3 4" | awk '{for (i=1; i<=NF; i++) {if (min=="") min=$(i); if (max=="") max=$(i); if ($(i)<min) min=$(i); if ($(i)>max) max=$(i)}} END {OFS="\t"; print "min","max";print min, max}'
如果您有更多行作为输入,min max
1 4
也会在阅读第一个awk
之后处理它们,例如此输入:
record
输出:
1 2 3 4
5 6 7 8
要防止这种情况并且仅在第一行上运行,您可以添加min max
1 8
之类的条件来仅处理第一行或在NR == 1
循环后添加exit
语句以停止在第一行之后处理输入。
答案 1 :(得分:2)
如果您只查看第1列,可以尝试:
awk '/^[[:digit:]].*/{if($1<min||!min){min=$1};if($1>max){max=$1}}END{print min,max}' dataset
脚本查找以数字开头的行,如果之前没有找到,则设置最小值或最大值。