Cố gắng sắp xếp trên hai lĩnh vực, thứ hai sau đó đầu tiên


106

Tôi đang cố gắng sắp xếp trên nhiều cột. Kết quả không như mong đợi.

Đây là dữ liệu của tôi (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

Sau đây hoạt động chính xác:

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

Nhưng, những điều sau đây không hoạt động như mong đợi:

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

Tôi đã cố gắng sắp xếp theo họ và sau đó bằng tên, nhưng bạn sẽ thấy Villamors không theo đúng thứ tự. Tôi đã hy vọng sắp xếp theo họ, và sau đó khi họ trùng khớp, sắp xếp theo tên.

Dường như có một cái gì đó về cách thức hoạt động này tôi không hiểu. Tôi có thể làm điều này theo cách khác tất nhiên (sử dụng awk), nhưng tôi muốn hiểu sắp xếp.

Tôi đang sử dụng shell Bash tiêu chuẩn trên Mac OS X.

Câu trả lời:


159

Một đặc điểm kỹ thuật chính như -k2có nghĩa là đưa tất cả các trường từ 2 đến cuối dòng vào tài khoản. Vì vậy, Villamor 44kết thúc trước Villamor 50. Vì hai cái này không bằng nhau, nên so sánh đầu tiên sort -k2 -k1là đủ để phân biệt hai dòng này và khóa sắp xếp thứ hai -k1không được gọi. Nếu hai Villamors có cùng độ tuổi, -k1sẽ khiến chúng được sắp xếp theo tên.

Để sắp xếp theo một cột duy nhất, sử dụng -k2,2làm thông số kỹ thuật chính. Điều này có nghĩa là sử dụng các trường từ # 2 đến # 2, tức là chỉ trường thứ hai.

sort -k2 -k3 <people.txtlà dư thừa: nó tương đương với sort -k2 <people.txt. Để sắp xếp theo tên cuối cùng, sau đó là tên, sau đó là tuổi, hãy chạy lệnh sau:

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

hoặc tương đương sort -k2,2 -k1 <people.txtvì chỉ có ba trường này và dấu phân cách là như nhau. Trong thực tế, bạn sẽ nhận được hiệu ứng tương tự từ sort -k2,2 <people.txt, bởi vì sortsử dụng toàn bộ dòng như là phương sách cuối cùng khi tất cả các khóa trong một tập hợp con của các dòng là giống hệt nhau.

Cũng lưu ý rằng dấu tách trường mặc định là sự chuyển đổi giữa không trống và trống, vì vậy các khóa sẽ bao gồm các khoảng trống hàng đầu (trong ví dụ của bạn, đối với dòng đầu tiên, khóa đầu tiên sẽ là "Emily", nhưng khóa thứ hai " Bedford". -btùy chọn để loại bỏ những khoảng trống:

sort -b -k2,2 -k1,1

Nó cũng có thể được thực hiện trên cơ sở mỗi khóa bằng cách thêm bcờ vào cuối đặc tả bắt đầu khóa:

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

Nhưng một điều cần lưu ý: ngay khi bạn thêm một cờ như vậy vào thông số kỹ thuật chính, các cờ toàn cầu (như -n, -r...) không còn áp dụng cho chúng, vì vậy tốt hơn là tránh trộn lẫn các cờ per-key và cờ toàn cầu.


6
Bạn đóng đinh nó. Tôi đã giả định (một điều nguy hiểm phải làm) rằng việc chỉ định -k1 có nghĩa là sử dụng trường 1, trong đó trường kết thúc tại dấu tách trường mặc định (dấu cách). Nhưng như bạn đã chỉ ra rõ ràng, tùy chọn k mong muốn bạn chỉ định điểm bắt đầu và điểm dừng của khóa, có thể hoặc không thể là một trường đơn lẻ. Giải pháp của bạn hoạt động hoàn hảo, và quan trọng hơn, tôi rõ ràng về lý do tại sao nó làm như vậy. Cảm ơn nhiều.
Harry

Đây là LỚN. Vì vậy, nhiều nguồn khác về KEYDEF nói về -k1 -k2 mà không nhấn mạnh tầm quan trọng của COMMA trong định dạng để giới hạn các cột được xem xét trong mỗi bước sắp xếp. Tôi đã bị mắc kẹt trong nhiều giờ cho đến khi tôi tìm thấy câu trả lời này. Và trang người đàn ông đang bối rối ở đây. Nó không giải thích rằng các vị trí "bắt đầu và dừng" được chỉ định bằng ký hiệu dấu phẩy. Cảm ơn bạn!
Jason Rohrer

16

Với GNU sortbạn làm như thế này, không chắc chắn về MacOS:

sort -k2,2 -k1 <people.txt

Cập nhật theo nhận xét. Trích dẫn từ 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
Bạn có thể vui lòng giải thích ký hiệu lạ này?
scai

1
Điều này khiến tôi suy nghĩ theo đúng đường - cảm ơn vì điều đó. Nhưng bạn không cần chỉ định điểm dừng cho -k thứ hai. Đó là -k2,2 -k1,1 nếu không điểm dừng được lấy là cuối dòng?
Harry

@TonyBedford, đúng rồi. Nhưng không chỉ định vị trí dừng sẽ không thay đổi kết quả cho đầu vào hiện tại của bạn, nhưng sẽ buộc tính nhất quán trong trường hợp bạn sẽ có nhiều dòng với trường 2 và 1. giống hệt nhau -k.
thao tác

1
@manatwork Điều đó không cần thiết; nếu tất cả các trường được chỉ định so sánh bằng nhau, sortsẽ so sánh toàn bộ dòng. Hoặc với GNU sortbạn có thể sử dụng -sđể sắp xếp ổn định.
augurar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.