根据列值排序并在文件中的相同 headers 之间取前 n 行

sort according to a column value and take first n lines between the same headers in a file

我有这样的输入;

header  score1  score2
item    1.3 100
item    2.3 170
item    4.0 35
header  score1  score2
item    2.9 45
item    1.7 55
header  score1  score2
item    0.5 60
header  score1  score2
header  score1  score2
item    1.4 75
item    2.5 120
item    3.7 200
header  score1  score2

我想单独考虑包括 'header' 在内的两条线之间的线。根据第二列中的值降序对行进行排序,并取值最高的前两行。另外,在顶部添加 header。已知该列表以“header score1 score2” .

开头

所以期望的输出是这样的;

header  score1  score2
item    4.0 35
item    2.3 170
header  score1  score2
item    2.9 45
item    1.7 55
header  score1  score2
item    0.5 60
header  score1  score2
header  score1  score2
item    3.7 200
item    2.5 120
header  score1  score2

我是一个相对较新的 awk 用户,所以我现在最好的方法是将步骤分开,然后逐步进行代码研究和应用。构建代码块是我现在不能申请的。

所以首先我必须单独考虑以“header”开头的行之间的每个间隔

1.

awk '/header/ {p=1;print;next}  /^header/ && p {p=0;print} p' input.txt

这输入了与预期相同的文件。我从中了解到,当有 'header 时,它正在打印它并继续打印到下一行,直到另一个 'header'

我正在使用此代码进行排序和取前 2 个:

2.

sort  -k2 -nr | head -2     # this should be without the header

我猜我必须以某种方式将第二个代码插入到第一个代码中,所以我将不胜感激任何对此的帮助。 谢谢

将 DSU (Decorate/Sort/Undecorate) 惯用法与任何 awk+sort+cut 结合使用:

$ cat tst.sh
#!/usr/bin/env bash

awk -v OFS='\t' '
     == "header" {
        blockNr++
    }
    { print blockNr, ( == "header" ? 0 : 1), [=10=] }
' "$@" |
sort -k1,1n -k2,2n -k4,4rn |
cut -f3- |
awk '
     == "header" {
        cnt = 0
    }
    cnt++ < 3
'

$ ./tst.sh file
header  score1  score2
item    4.0 35
item    2.3 170
header  score1  score2
item    2.9 45
item    1.7 55
header  score1  score2
item    0.5 60
header  score1  score2
header  score1  score2
item    3.7 200
item    2.5 120
header  score1  score2

有关 DSU 工作原理的详细信息,请参阅

另一个 awk 提供了一些支持且没有错误处理。

$ awk 'BEGIN    {cmd="sort -k2nr | head -2"} 
       /header/ {close(cmd); print; next} 
                {print | cmd}' file

header  score1  score2
item    4.0 35
item    2.3 170
header  score1  score2
item    2.9 45
item    1.7 55
header  score1  score2
item    0.5 60
header  score1  score2
header  score1  score2
item    3.7 200
item    2.5 120
header  score1  score2

使用 awk 将数据分区到 headers 的部分,并将排序和取 2 个函数委托给其他命令。

awk '
   /header/ {
        # Close pipe to sort when we get header.
        close("sort -r|head -2")
        # Copy header line to standard output.
        print
        next
   }
   {    # other lines to sort.
        print | "sort -r|head -2"
   }' input_file|column -t


header  score1  score2
item    4.0     35
item    2.3     170
header  score1  score2
item    2.9     45
item    1.7     55
header  score1  score2
item    0.5     60
header  score1  score2
header  score1  score2
item    3.7     200
item    2.5     120
header  score1  score2

花了我足够长的时间 — 概念是创建一个合成数组索引键用于排序

  • 合并来自多个列的排名排序,
  • 可以处理 floating point,让它们 mix-and 与 integers 匹配,并且
  • 保持 ASCII
  • 中的数字排名顺序
  • 足够宽,它只会在很短的时间内开始溢出 在没有 big-integer 库
  • 的情况下,大或小的数字
  • 最小化所需的比较操作数
* a single unified sort key compare
    
     instead of 

* having to go into each sub-key field when dealing with tie-breakers

代码

BEGIN {
 1      OFS = "\t"
 1      PROCINFO["sorted_in"] = "@ind_str_desc"

 1        __ = "[+-:]+"
 1      gsub("^|$", "[[:blank:]]", __)

 1      ____ = (((_*=_+=_^=_<_)^_)^--_)
 1         _ = _<_ 
}
# Rule(s)
 4  ($_)!~__ { # 2
 2      print
 2      while (($_) !~ __) {
 2          split("", ___)
 2          $_ = ""
 2          getline

    }
}
 4  {
 9      do {
 9          ___[sprintf("x%.12X%.12X",-(____/$(NF-!_)),-(____/$(NF)))] = $_
 9          getline
        } while (($_) ~ __)
 4      ______ = (! _) + (! _)
 9      for (_______ in ___) {
 9          if (-______ < +______--) { # 7

 7              print _______, ___[_______]
        }
    }
 4      split("", ___)
 4      print
 4      $_ = ""
}

输出

header  score1  score2
xFFFFFFFFFFC00000FFFFFFFFFFF8AF8B   item    4.0 35
xFFFFFFFFFF90B217FFFFFFFFFFFE7E7F   item    2.3 170

header  score1  score2
xFFFFFFFFFFA7B962FFFFFFFFFFFA4FA5   item    2.9 45
xFFFFFFFFFF69696AFFFFFFFFFFFB5870   item    1.7 55

header  score1  score2
xFFFFFFFFFE000000FFFFFFFFFFFBBBBC   item    0.5 60

header  score1  score2
header  score1  score2

xFFFFFFFFFFBACF92FFFFFFFFFFFEB852   item    3.7 200
xFFFFFFFFFF99999AFFFFFFFFFFFDDDDE   item    2.5 120

header  score1  score2