根据列值排序并在文件中的相同 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
我有这样的输入;
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