这是我的示例文本文件
[s] [K]
1 900
2 100
3 200
8 1000
1 80
55 12
6 90000
5 1
我需要在第 2 列中找到最大值,并在第 1 列中找到相应的值,然后从第 1 列的所有元素中减去该值。
我想要的输出是这样的
[s] [K]
-5 900
-4 100
-3 200
2 1000
-5 80
49 12
0 90000
-1 1
这是我的片段
awk 'function abs(x) {return x<0?-x:x}
FNR==1 { $1=$1; print; next }
{if(max<$2){max=$2;line=$1}}{print $1-line "\t"$2}' test.txt
不知何故,这没有给我正确的结果。我也希望第 2 列中的最小值具有相同的值。
答案1
您必须对数据进行两次遍历,首先找到最小值和最大值,然后进行计算:
awk 'BEGIN { OFS = "\t" }
FNR == NR { if (FNR > 1 && (min == "" || $2 < min)) { min = $2; minval = $1 }
if (FNR > 1 && (max == "" || $2 > max)) { max = $2; maxval = $1 }
next }
FNR == 1 { print "[s (-max)]", "[s (-min)]", "[K]"; next }
{ print $1 - maxval, $1 - minval, $2 }' file file
对于给定的数据,这将产生
[s (-max)] [s (-min)] [K]
-5 -4 900
-4 -3 100
-3 -2 200
2 3 1000
-5 -4 80
49 50 12
0 1 90000
-1 0 1
该awk
代码有四个块,我们将输入文件传递给它两次。第一个块 ( BEGIN
) 只是将输出字段分隔符设置为制表符。
第二个块 ( FNR == NR
) 将在第一次遍历文件期间对每一行执行,并跟踪第二列 (max
和min
) 中的最大值和最小值以及第一列 (maxval
和minval
) 中的相应值,并根据需要更新它们。在此块的末尾,next
用于跳过当前输入的脚本的其余部分。
NR
是当前记录的总体序号(“行号”),而FNR
是当前文件的相同编号。 将与仅第一次传递输入文件时NR
相同。FNR
FNR == 1
当刚刚从第二遍文件中读取第一行时,将执行第三个块 ( )。它只是打印出一个标题。我们将计算第一列的值减去minval
和 的值,因此我们添加一个新的列标题。maxval
最后一个块是无条件的,将在第二次遍历文件时执行第二行,并执行数据的实际计算和输出。
您可以通过将输出传递给以下方式获得稍微漂亮的输出column -s $'\t' -t
:
[s (-max)] [s (-min)] [K]
-5 -4 900
-4 -3 100
-3 -2 200
2 3 1000
-5 -4 80
49 50 12
0 1 90000
-1 0 1
答案2
$ cat tst.awk
BEGIN { OFS="\t" }
NR==1 { next }
NR==2 { maxVal = $2 }
NR==FNR {
if ($2 >= maxVal) {
maxSth = $1
maxVal = $2
}
next
}
{ print (FNR>1 ? ($1 - maxSth) : $1) , $2 }
$ awk -f tst.awk file file
[s] [K]
-5 900
-4 100
-3 200
2 1000
-5 80
49 12
0 90000
-1 1
答案3
也许是这样的?记录处理文件两次。
awk 'NR==FNR && NR>1 { max_col2=( max_col2>$2?max_col2:$2 ); max[$2]=$1;
min_col1=( min_col1>$1?min_col1:$1 ); min[$1]=$2; }
NR!=FNR && FNR>1{ print $1-max[max_col2], $2-min[min_col1]; }' OFS='\t' infile infile
-5 888
-4 88
-3 188
2 988
-5 68
49 0
0 89988
-1 -11