Mencoba mengurutkan pada dua bidang, kedua lalu pertama

106

Saya mencoba mengurutkan pada beberapa kolom. Hasilnya tidak seperti yang diharapkan.

Inilah data saya (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

Berikut ini berfungsi dengan benar:

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

Namun, berikut ini tidak berfungsi seperti yang diharapkan:

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

Saya mencoba untuk mengurutkan berdasarkan nama keluarga dan kemudian dengan nama depan, tetapi Anda akan melihat Villamors tidak dalam urutan yang benar. Saya berharap untuk mengurutkan berdasarkan nama keluarga, dan kemudian ketika nama keluarga cocok, untuk mengurutkan berdasarkan nama depan.

Sepertinya ada sesuatu tentang bagaimana ini seharusnya bekerja saya tidak mengerti. Saya bisa melakukan ini dengan cara lain tentu saja (menggunakan awk), tetapi saya ingin mengerti semacam itu.

Saya menggunakan Bash shell standar di Mac OS X.

Harry
sumber

Jawaban:

159

Spesifikasi kunci seperti -k2artinya untuk memperhitungkan semua bidang mulai dari 2 hingga akhir baris. Jadi Villamor 44berakhir sebelumnya Villamor 50. Karena keduanya tidak sama, perbandingan pertama sort -k2 -k1cukup untuk membedakan kedua baris ini, dan kunci sortir kedua -k1tidak dipanggil. Jika kedua Villamors memiliki usia yang sama, -k1akan menyebabkan mereka diurutkan berdasarkan nama depan.

Untuk mengurutkan berdasarkan satu kolom, gunakan -k2,2sebagai spesifikasi utama. Ini berarti menggunakan bidang dari # 2 ke # 2, yaitu hanya bidang kedua.

sort -k2 -k3 <people.txtredundan: sama dengan sort -k2 <people.txt. Untuk mengurutkan berdasarkan nama belakang, lalu nama depan, lalu usia, jalankan perintah berikut:

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

atau setara sort -k2,2 -k1 <people.txtkarena hanya ada tiga bidang ini dan pemisahnya sama. Bahkan, Anda akan mendapatkan efek yang sama dari sort -k2,2 <people.txt, karena sortmenggunakan seluruh baris sebagai pilihan terakhir ketika semua kunci dalam subset garis identik.

Perhatikan juga bahwa pemisah bidang default adalah transisi antara non-kosong dan kosong, sehingga tombol akan menyertakan bagian depan kosong (dalam contoh Anda, untuk baris pertama, kunci pertama adalah "Emily", tetapi kunci kedua " Bedford". Tambahkan -bpilihan untuk menghapus kosong itu:

sort -b -k2,2 -k1,1

Ini juga dapat dilakukan pada basis per-kunci dengan menambahkan bbendera di akhir spesifikasi mulai kunci:

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

Tetapi ada sesuatu yang perlu diingat: segera setelah Anda menambahkan satu bendera seperti itu ke spesifikasi kunci, bendera global (seperti -n, -r...) tidak lagi berlaku untuk mereka sehingga lebih baik untuk menghindari pencampuran bendera per kunci dan bendera global.

Gilles
sumber
6
Kamu berhasil. Saya berasumsi (hal yang berbahaya untuk dilakukan) yang menentukan -k1 berarti menggunakan bidang 1, di mana bidang berakhir di pemisah bidang default (spasi). Tetapi saat Anda menunjukkan dengan jelas, opsi k mengharapkan Anda untuk menentukan titik awal dan berhenti kunci, yang mungkin atau mungkin bukan satu bidang. Solusi Anda bekerja dengan sempurna, dan yang lebih penting, saya jelas mengapa itu terjadi. Terimakasih banyak.
Harry
Ini BESAR. Begitu banyak sumber lain tentang KEYDEF yang berbicara tentang -k1 -k2 tanpa menekankan pentingnya COMMA dalam format untuk membatasi kolom mana yang dipertimbangkan dalam setiap langkah penyortiran. Saya terjebak di ini selama berjam-jam sampai saya menemukan jawaban ini. Dan halaman manual membingungkan di sini. Itu tidak menjelaskan bahwa lokasi "mulai dan berhenti" ditentukan dengan nota koma. Terima kasih!
Jason Rohrer
16

Dengan GNU sortAnda melakukannya seperti ini, tidak yakin tentang MacOS:

sort -k2,2 -k1 <people.txt

Perbarui sesuai komentar. Dikutip dari 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.
manatwork
sumber
4
Bisakah Anda jelaskan notasi aneh ini?
scai
1
Ini membuat saya berpikir di jalur yang benar - terima kasih untuk itu. Tapi jangan Anda harus menentukan titik berhenti untuk -k kedua. Itu -k2,2 -k1,1 kalau tidak, titik berhenti diambil sebagai akhir dari garis?
Harry
@ TonyBedford, benar. Tetapi tidak menentukan posisi berhenti tidak akan mengubah hasil untuk input Anda saat ini, tetapi akan memaksakan konsistensi jika Anda akan memiliki banyak garis dengan bidang 2 dan 1. identik. Jadi saya lebih suka membiarkan yang terakhir -kmemasukkan sebanyak mungkin.
manatwork
1
@manatwork Itu tidak perlu; jika semua bidang yang ditentukan sama, sortakan membandingkan seluruh baris. Atau dengan GNU sortyang bisa Anda gunakan -suntuk sortir yang stabil.
augurar