bash 中的错误按不同的列排序?

bug in bash sort with different columns?

我正在处理一个文件,该文件包含 3 个值、一个 ID(如果您好奇的话,它们恰好是蛋白质 ID)、一个值,然后是另一个值。它是制表符分隔的,因此看起来像这样:

A2M     0.979569315988908       1
AACS    0.925340159491081       1
AAGAB   0.982296215686199       1
AAK1    0.736903840140103       1
AAMP    0.00589711816127862     0.138868449447202
AARS2   1       1
AARS    3.13300124295614e-05    0.00212792325492566
AARSD1  0.527417792161261       1
AASDH   0.869909252023668       1
AASDHPPT        0.763918221284724       1
AATF    0.691907759125663       1
ABAT    0.989693691462661       1
ABCA1   0.601194017450064       1
ABCA5   1       1
ABCA6   1       1

我有兴趣按字母顺序对这些 ID 进行排序并提取各种值。但是,我注意到 sort 对 ID 的排序方式不同,具体取决于我提取的内容。当我执行时:

    cut --fields\=1,2 input.txt|sort --key=1

生成的文件是:

A2M     0.979569315988908
AACS    0.925340159491081
AAGAB   0.982296215686199
AAK1    0.736903840140103
AAMP    0.00589711816127862
AARS2   1
AARS    3.13300124295614e-05 
AARSD1  0.527417792161261
AASDH   0.869909252023668
AASDHPPT        0.763918221284724
AATF    0.691907759125663
ABAT    0.989693691462661
ABCA1   0.601194017450064
ABCA5   1
ABCA6   1

但是当我执行时:

cut --fields\=1,3 input.txt|sort --key=1

我明白了

A2M     1
AACS    1
AAGAB   1
AAK1    1
AAMP    0.138868449447202
AARS    0.00212792325492566
AARS2   1
AARSD1  1
AASDH   1
AASDHPPT        1
AATF    1
ABAT    1
ABCA1   1
ABCA5   1
ABCA6   1

注意 AARS 和 AARS2 的位置调换了,这是不应该的,因为我只是根据第一列进行排序。我从 sort 中从未见过这样的行为,我已经使用 bash 一段时间了。这是一个错误,还是我做错了什么?

我认为排序是跳过选项卡...最终效果是 AARS0.00212792325492566 在 AARS21 之前,但 AARS21 在 AARS3.13300124295614e-05 之前。参见 this quesiton

以下应该有效

cut -f1,2 input.txt | sort -t$'\t'

不幸的是它没有,但我认为剥离标签是导致问题的原因。

--key=1 选项告诉 sort 使用从第一行到末尾的所有 "fields" 对输入进行排序。正如 @rici 首先观察到的,默认情况下这是一种区域设置敏感排序,并且在许多区域设置中,出于整理目的,空格会被忽略。这似乎就是这里发生的事情。

如果你只想 对蛋白质 ID 进行排序,那么应该是这样的:

cut --fields=1,2 input.txt | sort --key=1,1
cut --fields=1,3 input.txt | sort --key=1,1

@rici 解释了如何通过指定考虑空白的排序顺序来解决问题。

您正在使用区域设置感知排序(这是默认设置)。在许多语言环境中,空白在整理顺序中被明确忽略;结合您的键从第一个字段延伸到行尾的事实(这意味着 --key 选项是多余的),实际上意味着这些行被排序,就好像这些字段被连接起来而没有干预空格。

这里有一个更长的解释:

我的偏好是使用 LC_COLLATE=C sort ... 进行非语言环境感知排序。 (例如,定义 alias csort="LC_COLLATE=C sort")。在这种情况下,您也可以使用 -k1,1 显式终止排序键。如果您的第一列是唯一的,那就足够了。