Apa perbedaan antara "sort -u" dan "sort | uniq ”?

120

Di mana-mana saya melihat seseorang perlu mendapatkan daftar unik yang disortir, mereka selalu mengirim pesan sort | uniq. Saya belum pernah melihat contoh di mana seseorang menggunakannya sort -u. Kenapa tidak? Apa bedanya, dan mengapa lebih baik menggunakan uniq daripada bendera unik untuk disortir?

Benubird
sumber

Jawaban:

120

sort | uniqada sebelumnya sort -u, dan kompatibel dengan berbagai sistem yang lebih luas, meskipun hampir semua sistem modern mendukung -u- itu POSIX. Ini sebagian besar merupakan kemunduran ke hari-hari ketika sort -utidak ada (dan orang-orang tidak cenderung mengubah metode mereka jika cara yang mereka tahu terus bekerja, lihat saja ifconfigvs ipadopsi).

Keduanya kemungkinan digabungkan karena menghapus duplikat dalam file memerlukan pengurutan (setidaknya, dalam kasus standar), dan merupakan kasus penggunaan yang sangat umum. Ini juga lebih cepat secara internal karena dapat melakukan kedua operasi pada saat yang sama (dan karena itu tidak memerlukan IPC antara uniqdan sort). Terutama jika file tersebut besar, sort -ukemungkinan akan menggunakan lebih sedikit file perantara untuk mengurutkan data.

Di sistem saya, saya secara konsisten mendapatkan hasil seperti ini:

$ dd if=/dev/urandom of=/dev/shm/file bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 8.95208 s, 11.7 MB/s
$ time sort -u /dev/shm/file >/dev/null

real        0m0.500s
user        0m0.767s
sys         0m0.167s
$ time sort /dev/shm/file | uniq >/dev/null

real        0m0.772s
user        0m1.137s
sys         0m0.273s

Ini juga tidak menutupi kode kembali sort, yang mungkin penting (dalam kerang modern ada cara untuk mendapatkan ini, misalnya, bash's $PIPESTATUSarray, tapi ini tidak selalu benar).

Chris Down
sumber
31
Saya cenderung menggunakan sort | uniqkarena 9 kali dari 10, saya sebenarnya piping ke uniq -c.
Plutor
5
Perhatikan bahwa sort -uitu adalah bagian dari UNIX Edisi ke-7, sekitar tahun 1979. Versi sorttanpa dukungan -ubenar-benar kuno - atau ditulis tanpa memperhatikan standar de facto sebelum standar de jure POSIX. Lihat juga Urutkan Stack Overflow & uniq di shell Linux dari 2010.
Jonathan Leffler
3
+1 karena ip. Ini 2016 dan posting ini pada 2013, tetapi saya hanya tahu tentang ipperintah sekarang.
mati
4
Memberi +1 untuk "9 kali dari 10 Saya sebenarnya mem-piping ke uniq -c" (dan mungkin memipis sekali lagi ke sort -nr | head) Saya bertanya-tanya apa yang setara dengan sort | uniqdi Vim ketika saya tahu bahwa Vim memiliki :sort uperintah. Dan TIL sort -uada juga.
Zhuoyun Wei
Perhatikan bahwa ada perbedaan ketika menggunakan sort -n | uniqvs sort -n -u. Contohnya, trailing dan spasi putih terkemuka akan dianggap duplikat oleh sort -n -utetapi tidak oleh yang sebelumnya! echo -e 'test \n test' | sort -n -umengembalikan test, tetapi echo -e 'test \n test' | sort -n | uniqmengembalikan kedua baris.
mxmlnkn
46

Satu perbedaan adalah yang uniqmemiliki sejumlah opsi tambahan yang berguna, seperti melewatkan bidang untuk perbandingan dan menghitung jumlah pengulangan suatu nilai. sort's -ubendera hanya mengimplementasikan fungsionalitas dari tanpa hiasan uniqperintah.

CLF
sumber
3
+0.49 untuk jawaban yang bermanfaat, tetapi saya akan mengatakannya seperti "Output dari sort -utidak dapat diteruskan uniquntuk menggunakan beberapa opsi berguna yang terakhir, seperti melewatkan bidang untuk perbandingan dan menghitung jumlah pengulangan."
l0b0
15
+1 untuk mengimbangi penentang karena "tidak ada cara untuk melakukan ini langsung dari jenis" tidak menjawab pertanyaan ...
Izkata
42

Dengan sorts dan s yang sesuai dengan POSIX uniq(GNU uniqsaat ini tidak patuh dalam hal itu), ada perbedaan dalam hal itu yang sortmenggunakan algoritma penyatuan lokal untuk membandingkan string (biasanya akan digunakan strcoll()untuk membandingkan string) ketika uniqmemeriksa identitas nilai-byte (biasanya akan menggunakan strcmp()) .

Itu penting setidaknya untuk dua alasan.

  • Di beberapa lokal, terutama pada sistem GNU, ada karakter berbeda yang mengurutkan yang sama. Misalnya, di lokal en_US.UTF-8 pada sistem GNU, semua ①②③④⑤⑥⑦⑧⑨⑩ ... karakter dan banyak lainnya mengurutkan yang sama karena urutan pengurutannya tidak ditentukan. Angka 0123456789 arabic mengurutkan sama dengan rekan-rekan mereka Indikator Arab Timur (٠١٢٣٤٥٦٧٨٩).

    Sebab sort -u, ① mengurutkan sama dengan ② dan 0123 sama dengan ٠١٢٣ jadi sort -uhanya akan mempertahankan satu dari masing-masing, sedangkan untuk uniq(bukan GNU uniqyang menggunakan strcoll()(kecuali dengan -i)), ① berbeda dari ② dan 0123 berbeda dari ٠١٢٣, jadi uniqakan mempertimbangkan semua 4 unik.

  • strcollhanya dapat membandingkan string karakter yang valid (perilaku tidak terdefinisi sesuai POSIX ketika input memiliki urutan byte yang tidak membentuk karakter yang valid) sementara strcmp()tidak peduli tentang karakter karena hanya melakukan perbandingan byte ke byte. Jadi itulah alasan lain mengapa sort -umungkin tidak memberikan Anda semua baris unik jika beberapa dari mereka tidak membentuk teks yang valid. sort|uniq, sementara masih tidak ditentukan pada input non-teks, dalam praktiknya lebih cenderung memberi Anda garis unik karena alasan itu.

Disamping mereka kehalusan, satu hal yang belum dicatat sejauh ini adalah bahwa uniqmembandingkan seluruh baris leksikal, sedangkan sort's -umembandingkan berdasarkan spesifikasi semacam diberikan pada baris perintah.

$ printf '%s\n' 'a b' 'a c' | sort -uk 1,1
a b
$ printf '%s\n' 'a b' 'a c' | sort -k 1,1 | uniq
a b
a c

$ printf '%s\n' 0 -0 +0 00 '' | sort -n | uniq
0
-0
+0
00

$ printf '%s\n' 0 -0 +0 00 '' | sort -nu
0
Stéphane Chazelas
sumber
9

Saya lebih suka menggunakan sort | uniqkarena ketika saya mencoba menggunakan opsi -u(menghilangkan duplikat) untuk menghapus duplikat yang melibatkan string case campuran, tidak mudah untuk memahami hasilnya.

Catatan: sebelum Anda dapat menjalankan contoh di bawah ini, Anda perlu mensimulasikan urutan susunan standar C dengan melakukan hal berikut:

LC_ALL=C
export LC_ALL

Sebagai contoh, jika saya ingin menyortir file dan menghapus duplikat, sementara pada saat yang sama, menjaga perbedaan kasus string.

$ cat short      #file to sort
Pear
Pear
apple
pear
Apple

$ sort short     #normal sort (in normal C collating sequence)
Apple            #the lower case words are at the end
Pear
Pear
apple
pear

$ sort -f short  #correctly sorts ignoring the C collating order
Apple            #but duplicates are still there
apple
Pear
Pear
pear

$ sort -fu short #By adding the -u option to remove duplicates it is 
apple            #difficult to ascertain the logic that sort uses to remove
Pear             #duplicates(i.e., why did it remove pear instead of Pear?)

Kebingungan ini diselesaikan dengan tidak menggunakan -uopsi untuk menghapus duplikat. Penggunaan uniqlebih mudah diprediksi. Di bawah ini pertama-tama mengurutkan dan mengabaikan kasing dan kemudian meneruskannya ke uniquntuk menghapus duplikat.

$ sort -f short | uniq
Apple
apple
Pear
pear
Jerry Marbas
sumber
2
-uopsi sortoutput yang pertama menjalankan sama (lihat halaman manual). Dengan demikian sort -fumengambil kemunculan pertama dari setiap baris unik yang tidak sensitif huruf. Logika yang sortdigunakan untuk menghapus duplikat dapat diprediksi.
pallxk
3

Perbedaan lain yang saya temukan hari ini adalah ketika menyortir berdasarkan delimeter di mana sort -umenerapkan flag unik hanya pada kolom yang Anda sortir.

$ cat input.csv
3,World,1
1,Hello,1
2,Hello,1

$ cat input.csv | sort -t',' -k2 -u
1,Hello,1
3,World,1

$ cat input.csv | sort -t',' -k2 | uniq
1,Hello,1
2,Hello,1
3,World,1
Stefanos Chrs
sumber
Ini disebutkan dalam jawaban dari Stéphane Chazelas tapi saya suka contoh Anda jadi +1
roaima
Terima kasih telah menunjukkan @roaima, tidak terlalu jelas dalam jawaban itu
Stefanos Chrs