AWK在列中打印最小值的唯一值

时间:2018-03-27 08:35:32

标签: awk max min

我正在尝试使用awk执行以下操作:

输入文件:

6:28866209    NA     NA     NA     8.51368e-06   Y  
6:28856689    1   0.007828      1      1.50247e-06   X  
6:28856740    2     0.007828      1      1.50247e-06   Y   
6:28856889    3   7.51E-08      3     1.50247e-06   X

我想:

  • 获取第6列中每个独立值的第5列的最小值和最大值
  • 在文件末尾的每列5打印文件中的最小值

该文件可以有不同的N列,但所有列都至少有1-8列,这些列在我的每个文件中都是相同的。

输出:

6:28866209 NA NA NA 8.51368e-06 Y 8.51368e-06 1.50247e-06 
6:28856689 1 0.007828 1 1.50247e-06 X 1.50247e-061.50247e-06 
6:28856740 2 0.007828 1 1.50247e-06 Y 8.51368e-06 1.50247e-06 
6:28856889 3 7.51E-08 3 1.50247e-06 X 1.50247e-06 1.50247e-06

我尝试使用以下awk命令,但我只回到第6列中的第一个值...

awk 'BEGIN{OFS="\t";FS="\t"}{if (a[$6] == "") a[$6]=$5; if (a[$6] > $5) {a[$6]=$5}} {if (b[$6] == "") b[$6]=$5; if (b[$6] < $5) {b[$6]=$5}} END {if (i=$6) print $0,i,a[i],b[i]}' FILE

2 个答案:

答案 0 :(得分:0)

我认为最简单的方法是使用文件的双遍:

awk '(NR==FNR) && !($6 in min) { min[$6] = $5; max[$6] = $5; next }
     (NR==FNR) { m=min[$6]; M=max[$6];
                 min[$6] = $5<m ? $5 : m;
                 max[$6] = $5>M ? $5 : M;
                 next; }
     {print $0,min[$6],max[$6] }' <file> <file>

您的原始代码存在以下缺陷。 END语句仅在到达文件末尾时执行。您尝试打印完整文件,但未在解析中存储任何行。

对原始想法的更正是:

awk 'BEGIN{OFS="\t";FS="\t"}
     {if (a[$6] == "") a[$6]=$5;
      if (a[$6] > $5) {a[$6]=$5}
     }
     {if (b[$6] == "") b[$6]=$5;
      if (b[$6] < $5) {b[$6]=$5}
     }
     { c[NR]=$0; d[NR]=$6 }
     END { for (i=1;i<=NR;i++) print c[i],a[d[i]],b[d[i]] }' FILE

在这里,我将完整的FILE存储在数组c中,该数组由行号NR编制索引。我还将索引$6存储在数组d中。最后,我循环通过我存储的所有行并打印预期的内容。

  • 这种方法的缺点是你必须将整个文件存储在内存中。
  • 我的建议的缺点是,您必须从磁盘读取完整文件两次。

答案 1 :(得分:0)

awk 'FNR<NR{$7=m[$6];$8=M[$6];print;next} (!M[$6])||$5>M[$6]{M[$6]=$5}(!m[$6])||$5<m[$6]{m[$6]=$5}' file file

带评论

awk '
   # optional format
   BEGIN { OFS=FS="\t"}

   # for second pass (second file read)
   FNR<NR{
      # add a column 7 and 8 with value of min and max correponsing to column 5
      $7=m[$6];$8=M[$6]
      # print it and reda next line (don't go further in script)
      print;next}

   # this point is only reach by first file read
   # if Max is unknow or value 5  bigger than max
   (!M[$6])||$5>M[$6]{
      # set new max
      M[$6]=$5}
   # do the same for min
   (!m[$6])||$5<m[$6]{m[$6]=$5}
   # read 2 times the same file (first to find min/max, second to print it)
   ' sample.txt sample.txt