尝试对两个字段进行排序,然后是第二个

Har*_*rry 133 sort

我正在尝试对多列进行排序。结果并不如预期。

这是我的数据(people.txt):

Simon Strange 62
Pete Brown 37
Mark Brown 46
Stefan Heinz 52
Tony Bedford 50
John Strange 51
Fred Bloggs 22
James Bedford 21
Emily Bedford 18
Ana Villamor 44
Alice Villamor 50
Francis Chepstow 56
Run Code Online (Sandbox Code Playgroud)

以下工作正常:

bash-3.2$ sort -k2 -k3 <people.txt                                                                                                                    
Emily Bedford 18                                                                                                                                      
James Bedford 21                                                                                                                                      
Tony Bedford 50                                                                                                                                       
Fred Bloggs 22                                                                                                                                        
Pete Brown 37                                                                                                                                         
Mark Brown 46                                                                                                                                         
Francis Chepstow 56                                                                                                                                   
Stefan Heinz 52                                                                                                                                       
John Strange 51                                                                                                                                       
Simon Strange 62                                                                                                                                      
Ana Villamor 44                                                                                                                                       
Alice Villamor 50
Run Code Online (Sandbox Code Playgroud)

但是,以下内容无法按预期工作:

bash-3.2$ sort -k2 -k1 <people.txt                                        
Emily Bedford 18                                                                                                                                      
James Bedford 21                                                                                                                                      
Tony Bedford 50                                                                                                                                       
Fred Bloggs 22                                                                                                                                        
Pete Brown 37                                                                                                                                         
Mark Brown 46                                                                                                                                         
Francis Chepstow 56                                                                                                                                   
Stefan Heinz 52                                                                                                                                       
John Strange 51                                                                                                                                       
Simon Strange 62                                                                                                                                      
Ana Villamor 44                                                                                                                                       
Alice Villamor 50
Run Code Online (Sandbox Code Playgroud)

我试图按姓氏排序,然后按名字排序,但您会看到 Villamors 的顺序不正确。我希望按姓氏排序,然后当姓氏匹配时,按名字排序。

似乎我不明白这应该如何工作。我当然可以用另一种方式(使用 awk)来做到这一点,但我想了解排序。

我在 Mac OS X 上使用标准的 Bash shell。

Gil*_*il' 213

像关键规范一样-k2意味着考虑从 2 到行尾的所有字段。所以Villamor 44Villamor 50. 由于这两个不相等,所以第一次比较sort -k2 -k1就足以区分这两行,第二个排序键-k1没有被调用。如果两个Villamors的年龄相同,-k1就会导致他们按名字排序。

要按单列排序,请-k2,2用作键规范。这意味着使用从#2 到#2 的字段,即仅使用第二个字段。

sort -k2 -k3 <people.txt是多余的:它相当于sort -k2 <people.txt. 要按姓氏、名字、年龄排序,请运行以下命令:

sort -k2,2 -k1,1 <people.txt
Run Code Online (Sandbox Code Playgroud)

或者等效地,sort -k2,2 -k1 <people.txt因为只有这三个字段并且分隔符是相同的。事实上,您将从 中获得相同的效果sort -k2,2 <people.txt,因为sort当行子集中的所有键都相同时,将整行用作最后的手段。

另请注意,默认字段分隔符是非空白和空白之间的过渡,因此键将包括前导空白(在您的示例中,对于第一行,第一个键是"Emily",但第二个键是" Bedford"。添加-b去除这些空白的选项:

sort -b -k2,2 -k1,1
Run Code Online (Sandbox Code Playgroud)

也可以通过在b密钥启动规范的末尾添加标志来基于每个密钥来完成:

sort -k2b,2 -k1,1 <people.txt
Run Code Online (Sandbox Code Playgroud)

但是要记住一点:一旦您将一个这样的标志添加到密钥规范中,全局标志(如-n, -r...)就不再适用于它们,因此最好避免混合按键标志和全局标志。

  • 你钉了它。我曾假设(这是一件危险的事情)指定 -k1 将意味着使用字段 1,该字段以默认字段分隔符(空格)结尾。但是正如您明确指出的那样, k 选项希望您指定键的起点和终点,这可能是也可能不是单个字段。您的解决方案效果很好,更重要的是,我很清楚为什么会这样。非常感谢。 (11认同)
  • 这是巨大的。关于 KEYDEF 的许多其他来源都在谈论 -k1 -k2 ,而没有强调格式中逗号的重要性,以限制在每个排序步骤中考虑哪些列。我在这个问题上坚持了几个小时,直到我找到了这个答案。手册页在这里令人困惑。它没有解释“开始和停止”位置是用逗号表示法指定的。谢谢! (5认同)

man*_*ork 20

使用 GNU,sort您可以这样做,但不确定 MacOS:

sort -k2,2 -k1 <people.txt
Run Code Online (Sandbox Code Playgroud)

根据评论更新。引用自man sort

   -k, --key=KEYDEF
          sort via a key; KEYDEF gives location and type

   KEYDEF is F[.C][OPTS][,F[.C][OPTS]] for start and stop position, where
   F is a field number and C a character position in the field; both are
   origin 1, and the stop position defaults to the line's end.
Run Code Online (Sandbox Code Playgroud)

  • 你能解释一下这个奇怪的符号吗? (8认同)
  • @manatwork 那应该没有必要;如果所有指定的字段比较相等,`sort` 将比较整行。或者使用 GNU `sort`,您可以使用 `-s` 进行稳定排序。 (2认同)