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


106

我正在尝试对多个列进行排序。结果不符合预期。

这是我的数据(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

以下内容可以正常工作:

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

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

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

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

我似乎不知道这应该如何工作。当然,我可以使用另一种方式(使用awk)来执行此操作,但是我想了解排序。

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

Answers:


159

像这样的键规范-k2意味着要考虑从2到行尾的所有字段。因此Villamor 44结束之前Villamor 50。由于这两个不相等,因此第一个比较in 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

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

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

sort -b -k2,2 -k1,1

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

sort -k2b,2 -k1,1 <people.txt

可是,我要记住:只要你加入一个这样的标志密钥规范,全局标志(如-n-r...)不再适用于他们,所以最好还是避免每个键标志和全局标志混合。


6
你钉了 我假设(做一件危险的事)指定-k1表示使用字段1,其中该字段在默认字段分隔符(空格)处结束。但是,正如您明确指出的那样,k选项期望您指定键的起点和终点,这些起点可能不是一个字段。您的解决方案运行完美,更重要的是,我很清楚为什么这样做。非常感谢。
哈利

这是巨大的。关于KEYDEF的许多其他资料都谈到了-k1 -k2,却没有强调COMMA在格式上的重要性,以限制在每个排序步骤中考虑哪些列。我被困了几个小时直到找到答案。手册页在这里令人困惑。它没有解释用逗号来指定“开始和停止”位置。谢谢!
杰森罗勒

16

使用GNU,sort您可以这样操作,不确定MacOS:

sort -k2,2 -k1 <people.txt

根据评论更新。引用自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.

4
您能解释一下这个奇怪的概念吗?
scai 2012年

1
这让我沿着正确的方向思考-谢谢。但是,您不需要为第二个-k指定停止点。那是-k2,2 -k1,1,否则将停止点当作行尾?
哈利

@TonyBedford,正确。但是,如果不指定停止位置,则不会更改当前输入的结果,但会强制保持一致性,以防万一您有多行具有相同字段2和1的行。因此,我希望允许最后一行-k包含尽可能多的行。
manatwork,2012年

1
@manatwork没必要;如果所有指定的字段比较相等,sort则将比较整行。或者使用GNU sort,可以-s用于稳定排序。
2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.