亲爱的大家我有一个大的数据文件可以说文件.dat,它包含两列
例如 file.dat (显示几行)
0.0000 -23.4334
0.0289 -23.4760
0.0578 -23.5187
0.0867 -23.5616
0.1157 -23.6045
0.1446 -23.6473
0.1735 -23.6900
0.2024 -23.7324
0.2313 -23.7745
0.2602 -23.8162
0.2892 -23.8574
0.3181 -23.8980
0.3470 -23.9379
0.3759 -23.9772
0.4048 -24.0156
0.4337 -24.0532
0.4627 -24.0898
0.4916 -24.1254
note: data file has a blank line at the end of the file
预期成绩
我想从列中查找/提取最大值和最小值,例如第 1 列
max - 0.4916
min - 0.0000
同样第2栏
max - -23.4334
min - -24.1254
不完整的解决方案(不适用于第 2 列)
对于第 1 列
awk 'BEGIN{min=9}{for(i=1;i<=1;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
0.0000
cat file.dat | awk '{if ($1 > max) max=$1}END{print max}'
0.4916
对于第 2 列
awk 'BEGIN{min=9}{for(i=2;i<=2;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
-23.4334
cat file.dat | awk '{if ($2 > max) max=$2}END{print max}'
**no output showing**
问题
请帮我找到第 2 列的最小值和最大值 注意:数据文件的末尾有一个空行
答案1
您的代码中的问题,
awk 'BEGIN{min=9}{for(i=2;i<=2;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
...是您exit
在处理第一行输入后立即执行的操作。你的中间块需要被触发每一个线。然后,END
您可以在块中打印找到的值。您可以在另一个代码片段中执行此操作:
awk '{if ($1 > max) max=$1}END{print max}'
另一个问题是您min
使用幻数进行初始化(我引用的第一个代码中为 9,第二段代码中为 0;如果在计算中使用未显式初始化的变量,则其值为 0)。如果这个幻数不在实际数据的数字范围内,那么计算出的最小值和/或最大值将是错误的。最好将 min 和 max 都初始化为数据中找到的某个值。
保持对...的跟踪两个都最小值和最大值,您需要两个变量,并且需要根据文件中的每一行数据检查这两个变量,以查看它们是否需要更新。
由于awk
支持数组,因此将数组用于min
和是很自然的max
,每列一个数组元素。这就是我在下面的代码中所做的。
推广到任意数量的列:
NF == 0 {
# Skip any line that does not have data
next
}
!initialized {
# Initialize the max and min for each column from the
# data on the first line of input that has data.
# Then immediately skip to next line.
nf = NF
for (i = 1; i <= nf; ++i)
max[i] = min[i] = $i
initialized = 1
next
}
{
# Loop over the columns to see if the max and/or min
# values need updating.
for (i = 1; i <= nf; ++i) {
if (max[i] < $i) max[i] = $i
if (min[i] > $i) min[i] = $i
}
}
END {
# Output max and min values for each column.
for (i = 1; i <= nf; ++i)
printf("Column %d: min=%s, max=%s\n", i, min[i], max[i])
}
鉴于此脚本和问题中的数据:
$ awk -f script.awk file
Column 1: min=0.0000, max=0.4916
Column 2: min=-24.1254, max=-23.4334
第一个块(对所有行执行)的条件NF == 0
是确保我们跳过空白行。该测试的意思是“如果该行上有零个数据字段(列)”。该变量initialized
从一开始就为零(逻辑上错误的),但将被设置为一(逻辑上真的)一旦读取到第一行数据。
该变量在我们初始化和值的行上nf
被初始化为NF
(字段数)。这样即使最后一行的字段为零,块中的输出也能正常工作。min
max
END
答案2
实际上,您可以将所有指令合并到一个awk
程序中:
awk 'NR==1{min1=max1=$1;min2=max2=$2}\
NR>1 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat
这将使用第一行的相应值(带有条件的规则NR==1
)初始化两列的最小值和最大值,然后扫描连续行以查看这些值是否分别大于当前最大值/小于当前最小值(有条件的规则NR>1
)。
在文件末尾(带有条件的规则END
),它打印结果。
注意这假设没有空行。如果有,则必须将条件替换NR>1
为NR>1 && NF>0
。如果可以有空行在第一个之前, 使用
awk '!init && NF>0 {init=1; min1=max1=$1; min2=max2=$2} \
init==1 && NF>0 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat
这将使用一个变量init
来检查是否已找到非空行,并使用第一个非空行的内容来预设两列的当前最大值/最小值。仅当init
设置(在此初始化之后)时,才会考虑输入该统计数据(非空)行。
一般来说,您永远不需要cat
一个文件并将结果通过管道传输到awk
.
答案3
使用datamash
和printf
:
for f in 1 2 ; do printf 'Column #%s\nmax - %s\nmin - %s\n\n' $f \
$(datamash -W max $f min $f < file.dat); done
...或者没有循环:
printf 'Column #%s\nmax - %s\nmin - %s\n\n' \
$(datamash -W max 1 min 1 max 2 min 2 < file.dat |
tr -s '\t' '\n' | paste - - | nl)
输出:
Column #1
max - 0.4916
min - 0
Column #2
max - -23.4334
min - -24.1254
答案4
这适用于第 1 列(它计算平均值最大值和最小值)
sort -n -k 1 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1} END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'
这是第 2 栏
sort -n -k 2 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1} END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'