Bagaimana uniq tidak cukup unik sehingga ada juga uniq --unique?

35

Berikut adalah perintah pada file acak dari pastebin :

wget -qO - http://pastebin.com/0cSPs9LR | wc -l
350
wget -qO - http://pastebin.com/0cSPs9LR | sort -u | wc -l
287
wget -qO - http://pastebin.com/0cSPs9LR | sort | uniq | wc -l
287
wget -qO - http://pastebin.com/0cSPs9LR | sort | uniq -u | wc -l
258

Halaman manual tidak jelas tentang apa yang dilakukan -ubendera. Ada saran?

ketertarikan
sumber
4
Coba urutkan | uniq -d | wc -l dan Anda mungkin melihat perbedaannya. :)
stoeff

Jawaban:

42

Versi pendek:

  • uniq, tanpa -u, membuat setiap baris output menjadi unik.
  • uniq -uhanya mencetak setiap baris unik dari input .

Versi yang sedikit lebih lama:

uniqadalah untuk berurusan dengan file-file yang memiliki duplikat baris, dan hanya ketika baris-baris tersebut muncul berturut-turut dalam input. Jadi, untuk keperluannya, garis yang unik adalah yang tidak terduplikasi dengan segera.

( uniqmemiliki memori jangka pendek yang sangat terbatas; ia tidak akan pernah ingat apakah suatu baris muncul lebih awal pada input, kecuali jika itu adalah baris yang sebelumnya langsung - inilah mengapa uniqsangat sering dipasangkan dengan sort).

Ketika bertemu dengan garis duplikat uniq,, tanpa -uarg, mencetak satu salinan dari garis itu. (Ini membuat setiap baris output menjadi unik ).

Dengan -uargumen itu, ia mencetak nol salinan dari garis itu - menjalankan duplikat hanya dihilangkan dari output.

Ian Clelland
sumber
1
Saya benar-benar berharap ada opsi untuk tidak memerlukan penyortiran. Tetapi itu akan membutuhkan menyimpan seluruh file dalam memori (atau melakukan banyak pembukuan dengan hash dan offset jika sumbernya adalah file normal)
Random832
3
@ Random832: dan itu akan membutuhkan memutuskan mana dari dupes untuk menjaga (pertama, terakhir, sesuatu yang lain, dapat dikonfigurasi), dan keputusan itu akan mempengaruhi algoritma secara global. Kerumitan.
Steve Jessop
1
@ Random832: jika hanya tentang jumlah karakter yang harus diketik, Anda dapat menggunakannya sort -usebagai ganti sort | uniq.
oliver
@oliver Saya kadang-kadang menginginkan kemampuan untuk menjaga instance pertama dari baris apa pun tanpa menata ulang, dan skrip tertulis untuk melakukannya.
Acak 832
1
@ DVD: jika versi Anda uniqmelakukan normalisasi dan pengumpulan, ya. Tetapi meskipun demikian itu hanya pertimbangan lokal - Anda tahu di mana dalam output yang diurutkan garis akan muncul, dan hanya harus memilih mana dari beberapa baris yang berdekatan untuk disimpan. Jika input tidak diurutkan maka keputusan mempengaruhi seluruh operasi uniqifying, misalnya jika Anda akan menyimpan duplikat terakhir maka Anda tidak dapat menampilkan apa pun sampai Anda telah membaca baris terakhir dari input ...
Steve Jessop
53

uniqdengan -umelompati setiap baris yang memiliki duplikat. Demikian:

$ printf "%s\n" 1 1 2 3 | uniq
1
2
3
$ printf "%s\n" 1 1 2 3 | uniq -u
2
3

Biasanya, uniqmencetak garis paling banyak satu kali (dengan asumsi input diurutkan). Pilihan ini sebenarnya mencetak garis yang benar-benar unik (setelah tidak muncul lagi).

muru
sumber
11
Yaitu, uniqbisa disebut distinct, karena ia mencetak semua garis yang berbeda, sedangkan uniq -umencetak semua garis yang unik.
Steve Jessop
Ini tidak benar-benar unik dengan GNU uniqdi beberapa lokal.
cuonglm
Saya pasti telah membaca jawaban yang diterima beberapa kali, tetapi itu tidak meresap. Contoh dan paragraf Anda setelah itu membuatnya sangat jelas (dan kembali dan membaca kembali jawaban yang diterima, saya mengerti juga) :)
Madivad
18

uniq POSIX spec menggambarkannya dengan jelas:

-u
    Suppress the writing of lines that are repeated in the input.

-uopsi buat uniquntuk tidak mencetak garis yang berulang.

Sebagian besar uniqimplementasi menggunakan perbandingan byte, sedangkan GNU uniqmenggunakan urutan pemeriksaan untuk memfilter garis yang diduplikasi. Sehingga dapat menghasilkan hasil yang salah di beberapa lokal, misalnya di en_US.UTF-8lokal:

$ printf '%b\n' '\U2460' '\U2461' | uniq
①

dan tidak -umemberi Anda garis:

$ printf '%b\n' '\U2460' '\U2461' | uniq -u
<blank>

Jadi, Anda harus mengatur lokal Cuntuk mendapatkan perbandingan byte:

$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=C uniq
①
②
cuonglm
sumber
3
Perhatikan bahwa apa yang salah di sini tidak sebanyak uniq(meskipun tampaknya maksud POSIX adalah bahwa ia harus melakukan perbandingan byte daripada strcoll () perbandingan seperti dalam sort -u) sebagai lokal yang keliru ① menyortir sama dengan ②. Setidaknya GNU uniqkonsisten dengan sort -u.
Stéphane Chazelas
@ StéphaneChazelas - di mana dalam spec yang dibuat jelas?
mikeserv
Tentang uniqdiperlukan untuk melakukan memcmp / strcmp sebagai lawan dari strcoll, itu tidak terlalu jelas bagi saya tapi itu untuk Geoff . Tentang lokal GNU yang memiliki ① pengurutan sama dengan ②, itu jelas bug karena tidak ada alasan mengapa mereka harus mengurutkan yang sama. Itu diizinkan oleh POSIX tetapi ada beberapa perubahan yang datang .
Stéphane Chazelas
8

normal:

echo "a b a b c c c" | tr ' ' '\n'
a
b
a
b
c
c
c

uniq: tidak ada dua baris berulang berikutnya

echo "a b a b c c c" | tr ' ' '\n' | uniq
a
b
a
b
c

disortir

echo "a b a b c c c" | tr ' ' '\n' | sort
a
a
b
b
c
c
c

sort -u: tidak ada dua baris yang berulang

echo "a b a b c c c" | tr ' ' '\n' | sort -u
a
b
c

sort / uniq: semuanya berbeda

echo "a b a b c c c" | tr ' ' '\n' | sort | uniq
a
b
c

menghitung kejadian berbeda

echo "a b a b c c c" | tr ' ' '\n' | sort | uniq -c
2 a
2 b
3 c

hanya baris yang tidak diulang (tidak diurutkan terlebih dahulu)

echo "a b a b c c c" | tr ' ' '\n' | uniq -u
a
b
a
b

hanya garis yang tidak diulang (setelah disortir)

echo "a b a b c c c Z" | tr ' ' '\n' | sort | uniq -u
Z

uniq -d: hanya mencetak garis duplikat, satu untuk setiap grup

echo "a b a b c c c" | tr ' ' '\n' | uniq -d
c

.. dihitung

echo "a b a b c c c" | tr ' ' '\n' | uniq -dc
3 c
selamat tinggal
sumber
contoh jelas yang bagus :)
Madivad