sort -k#。#n不同于sort -k#。# - n?

时间:2015-07-17 13:21:54

标签: sorting unix

[编辑添加-b,我已经尝试过无效]

我有一个文件,在我想要的括号中有一列数字 排序,像这样:

x (10)
x (11)
x (1)
x (2)

我认为sort -b -k 2.2n会起作用。但事实并非如此。 但是我发现sort -b -k 2.2 -n确实有效,产生了 期望的输出

x (1)
x (2)
x (10)
x (11)

任何人都可以解释原因吗?我知道-n将所有列视为数字 (不仅仅是选定的那些),但我很惊讶这里有所作为。 我真的认为-k 2.2n会对第二列进行排序 在数字上,从第二个位置开始,我没有 明白为什么它不起作用。 (虽然sort的细微差别有 当然eluded me before。)

这是“sort(GNU coreutils)5.93”,如果它有所作为。 [后来我在另一台使用coreutils 8.5的机器上尝试过它并看到了相同的结果。]

1 个答案:

答案 0 :(得分:3)

Coreutils 5.93真的很老了。较新的版本有一个很好的--debug选项,可以显示您的字段选择器如何应用于每一行。

您遇到的问题是,默认情况下,排序字段拆分包括字段之间的空格,作为以下字段的一部分。因此,在您的情况下,第二个字段是" (1)",带有前导空格,因此-k2.2正在选择以括号开头的子字符串,然后无法将其识别为数字。

您可以通过添加b标志来解决此问题。 sort -k2.2nbsort -k2.2 -n -b应该有效。

在最新的coreutils(8.23)上,我无法重现您sort -k2.2 -n的行为 - 它与sort -k2.2n的行为相同,无法匹配数字并且退回到& #34;整行字符串比较"排序

更新(3):现在我已经在版本5.93,8.13和8.23中复制了您的结果。并且有一个明确的解释。

我的两条建议(sort -k2.2nbsort -k2.2 -n -b)都有效。您的sort -b -k2.2n没有。在支持--debug的版本中,它说:

$ printf '%s\n' 'x ('{1,2,10,11}')'|sort -k 2.2n -b --debug
sort: using simple byte comparison
sort: leading blanks are significant in key 1; consider also specifying 'b'
sort: key 1 is numeric and spans multiple fields
sort: option '-b' is ignored
x (1)
  ^ no match for key
_____
x (10)
  ^ no match for key
______
x (11)
  ^ no match for key
______
x (2)
  ^ no match for key
_____
$

option '-b' is ignored是对正在发生的事情的解释。只要将一个标志(n)附加到-k给出的密钥规范,就会忽略所有全局指定的标记。

coreutils的GNU info文档明确指出了这一点(我用粗体标记了重要部分):

  

以下选项会影响输出行的顺序。它们可以全局指定,也可以作为特定关键字段的一部分。如果未指定关键字段,则全局选项适用于整行的比较;否则全局选项由关键字段继承,但未指定任何特殊选项。在'sort'的POSIX前版本中,全局选项仅影响以后的关键字段,因此可移植的shell脚本应该首先指定全局选项。

-b位于后面的列表中。)

手册页的措辞不太明确:

  

KEYDEF是开始和停止位置的F [.C] [OPTS] [,F [.C] [OPTS]],其中F是字段编号,C是字段中的字符位置;两者都是原点1,停止位置默认为行的结尾。如果-t和-b都不起作用,则字段中的字符将从前一个空格的开头计算。 OPTS是一个或多个单字母排序选项[bdfgiMhnRrV],它覆盖该键的全局排序选项。如果没有给出密钥,请使用整行作为密钥。

您可以轻松地将其解释为每个单字母选项仅覆盖同一个字母的全局选项。但你错了......

POSIX definition非常清楚(我再次将重要部分加粗):

  

以下选项将覆盖默认排序规则。当订购选项独立于任何关键字段规范出现时,所请求的字段排序规则应全局应用于所有排序键。当附加到特定密钥(请参阅-k)时,指定的排序选项应覆盖该密钥的所有全局排序选项

关于它的唯一有点不清楚的部分是-b没有出现在该段落后面的列表中。该列表后面有一个单句,引入了另一个包含-b-t选项的列表,因此您可能会认为-b不属于&的范围#34;覆盖所有全球订购选项"规则。

毕竟,-b不是排序选项,而是字段拆分选项,当您将其附加到键定义时,您可以将其单独应用于开头,结尾或两者。所以它不像任何其他选项。但至少在GNU实现中, 遵循"覆盖所有全局排序选项"规则。