我想对文件进行排序。
输入:
I1, -2
I2, -6
I2, -9
I1, -8
I1, -1
I3, -7
I2, -4
I3, -4
输出 :
I2, -9
I2, -6
I2, -4
I1, -8
I1, -2
I1, -1
I3, -7
I3, -4
如何得到下面的输出?
答案1
一个肮脏的解决方案是:
<infile sort -t, -rk2,2 \
|awk -F, '{ seen[$1]= (seen[$1]==""? "\0":seen[$1] ORS) $0 }
END{ for (x in seen) print seen[x] }' \
|sort -z -t, -rk2,2 \
|tr -d '\0'
分解:
<infile sort -t, -rk2,2
这会对r
输入文件进行相反的排序infile
第二个字段(逗号是分隔符)作为k
ey 字段。这awk代码只是对具有相同第一列的记录重新排序;我们将每组分开无效的特点
\0
。sort -z -t, -rk2,2
-z
这个反向排序对第二个字段和逗号分隔字段上的 这些块(用空字符分隔;我们用 告诉排序命令)进行排序。请在运行此步骤之前查看以下输出并添加cat -A
您将看到:^@I1, -8$ I1, -2$ I1, -1$ ^@I2, -9$ I2, -6$ I2, -4$ ^@I3, -7$ I3, -4$
^@
字符代表空字符,sort -z
上面的输入看到的是这样的(我这样做是为了人类可读和更好的理解)^@I1, -8$ I1, -2$ I1, -1$ ^@I2, -9$ I2, -6$ I2, -4$ ^@I3, -7$ I3, -4$
你明白了,上面的排序命令看到第二个字段如下
-8$ I1 -9$ I2 -7$ I3
...并对这些进行反向排序,结果更改为以下内容:
^@I2, -9$ I2, -6$ I2, -4$ ^@I1, -8$ I1, -2$ I1, -1$ ^@I3, -7$ I3, -4$
...如果我们返回结构,我们实际上有这个:
^@I2, -9$ I2, -6$ I2, -4$ ^@I1, -8$ I1, -2$ I1, -1$ ^@I3, -7$ I3, -4$
tr -d '\0'
这会从结果中删除添加的空字符,最终输出为:I2, -9 I2, -6 I2, -4 I1, -8 I1, -2 I1, -1 I3, -7 I3, -4
答案2
使用 GNU awk
:
gawk '
grp[$1] == "" || $2 < grp[$1] { grp[$1] = $2 }
{ val[$1][$2] }
END {
PROCINFO["sorted_in"] = "@val_num_asc"
for (i in grp) {
PROCINFO["sorted_in"] = "@ind_num_asc"
for (j in val[i]) print i,j
}
}' ./file
这个想法是:
grp
为数组中第 1 列的每个不同值存储第 2 列的最小值- 将每一行存储在二维数组中
val
,以便方便地检索第 1 列的每个不同值的第 2 列的值(您还可以使用val[$1][$2] = $0
和print val[i][j]
来保留数据的原始间距) - 用于根据其元素的值
PROCINFO["sorted_in"]
遍历数组,并根据其索引的值遍历(单维)数组(始终按升序排序)。 请注意,如果您想要更改与第 2 列共享相同最小值的第 1 列值的排序顺序(例如,如果您添加到样本数据并希望在输出之前排序) ,您可能需要定义自己的排序函数)。grp
val[i]
I4, -9
I4
I2
一种便携式替代方案,基于施瓦茨变换, 或许:
sort -k2,2n ./file |
awk '
grp[$1] == "" { grp[$1] = $2 }
{ print grp[$1] "," $0 }' |
sort -t, -k 1,1n -k 2,2 -k 3,3n |
cut -d, -f2-
其中,第 2 列的“每组”(即相对于第 1 列的值)最小值被添加到每行前面,允许基于每组最小值 ( -9
、-8
、-7
)、列的值进行后续排序1(以保持按其分组的行),并且第 2 列的值
awk
提供有排序的数据,以使脚本更简单:对于每行,当满足该行时,每组的最小值已经知道,无需存储某些结构中的行并将它们打印在一个END
块中(或处理文件两次)。