อะไรคือความแตกต่างระหว่าง "sort -u" และ "sort | UNIQ”?


120

ทุกที่ที่ฉันเห็นคนที่ต้องการเรียงลำดับรายการที่ไม่ซ้ำใครพวกเขาจะไปถึงsort | uniqเสมอ ฉันไม่เคยเห็นตัวอย่างที่มีคนใช้sort -uแทน ทำไมจะไม่ล่ะ? ความแตกต่างคืออะไรและทำไมการใช้ uniq จึงดีกว่าการจัดเรียงค่าสถานะเฉพาะ


คำตอบ:


120

sort | uniqมีอยู่ก่อนsort -uและเข้ากันได้กับช่วงกว้างของระบบแม้ว่าระบบที่ทันสมัยเกือบทั้งหมดรองรับ-u- มันเป็น POSIX มันเป็นส่วนใหญ่ย้อนกลับไปวันเมื่อsort -uไม่ได้อยู่ (และคนที่ไม่ได้มีแนวโน้มที่จะเปลี่ยนวิธีการของพวกเขาหากวิธีการที่พวกเขารู้ว่ายังคงทำงานเพียงมองifconfigเทียบกับipการนำไปใช้)

ทั้งสองมีแนวโน้มที่จะรวมกันเนื่องจากการลบรายการที่ซ้ำกันในไฟล์ต้องมีการเรียงลำดับ (อย่างน้อยในกรณีมาตรฐาน) และเป็นกรณีที่ใช้กันทั่วไปอย่างมากในการเรียง นอกจากนี้ยังเร็วขึ้นภายในเนื่องจากความสามารถในการดำเนินการทั้งสองในเวลาเดียวกัน (และเนื่องจากความจริงที่ว่ามันไม่ต้องการ IPC ระหว่างuniqและsort) โดยเฉพาะอย่างยิ่งหากไฟล์มีขนาดใหญ่sort -uมีแนวโน้มว่าจะใช้ไฟล์ระดับกลางน้อยลงเพื่อจัดเรียงข้อมูล

ในระบบของฉันฉันได้รับผลลัพธ์เช่นนี้อย่างสม่ำเสมอ:

$ 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

นอกจากนี้ยังไม่หน้ากากรหัสการกลับมาของsortซึ่งอาจจะมีความสำคัญ (ในเปลือกหอยที่ทันสมัยมีวิธีที่จะได้รับนี้เช่นbash's $PIPESTATUSอาร์เรย์ แต่เรื่องนี้ไม่เป็นความจริงเสมอ)


31
ฉันมักจะใช้sort | uniqเพราะ 9 ครั้งจาก 10 ฉันไปป์ไลน์จริงuniq -c
พลูโต

5
โปรดทราบว่าsort -uเป็นส่วนหนึ่งของ UNIX รุ่นที่ 7 ประมาณปี 1979 รุ่นที่sortไม่มีการสนับสนุน-uเป็นสิ่งที่ล้าสมัยอย่างแท้จริง - หรือเขียนขึ้นโดยไม่สนใจมาตรฐาน de พฤตินัยก่อนมาตรฐานทางกฎหมายของ POSIX ดูเพิ่มเติม Stack Overflow Sort & uniq ใน Linux shellจากปี 2010
Jonathan Leffler

3
+1 ipเพราะ มันเป็นปี 2016 และโพสต์นี้ในปี 2013 แต่ฉันเพิ่งรู้เกี่ยวกับipคำสั่งตอนนี้
dieend

4
+1 สำหรับ "9 ครั้ง 10 ฉันกำลังไปที่uniq -c" (และอาจจะเพิ่มอีกครั้งเพื่อsort -nr | head) ฉันสงสัยว่าอะไรเป็นสิ่งที่เทียบเท่ากับsort | uniqในกลุ่มเมื่อฉันพบว่ากลุ่มมี:sort uคำสั่ง และ TIL ก็sort -uมีอยู่เช่นกัน
Zhuoyun Wei

โปรดทราบว่ามีความแตกต่างเมื่อใช้กับsort -n | uniq sort -n -uยกตัวอย่างเช่นการต่อท้ายและช่องว่างนำหน้าจะถูกมองว่าเป็นสิ่งที่ซ้ำกันsort -n -uแต่ไม่ใช่ในอดีต! echo -e 'test \n test' | sort -n -uผลตอบแทนtestแต่echo -e 'test \n test' | sort -n | uniqกลับทั้งสองบรรทัด
mxmlnkn

46

ข้อแตกต่างประการหนึ่งคือuniqมีตัวเลือกเพิ่มเติมที่มีประโยชน์มากมายเช่นการข้ามเขตข้อมูลสำหรับการเปรียบเทียบและการนับจำนวนการทำซ้ำของค่า sortการ-uตั้งค่าสถานะใช้การทำงานของuniqคำสั่งที่ไม่มีการตกแต่งเท่านั้น


3
+0.49 สำหรับคำตอบที่มีประโยชน์ แต่ฉันต้องการวลีว่า "ผลลัพธ์ของsort -uไม่สามารถส่งผ่านไปuniqยังเพื่อใช้ตัวเลือกที่เป็นประโยชน์บางอย่างของหลังเช่นการข้ามเขตข้อมูลสำหรับการเปรียบเทียบและนับจำนวนการทำซ้ำ"
l0b0

15
+1 เพื่อชดเชยนักการตลาดเนื่องจาก "ไม่มีวิธีการทำสิ่งนี้โดยตรงจากการจัดเรียง" จะตอบคำถาม ...
Izkata

42

ด้วยตาม POSIX sortและuniqs (GNU uniqปัจจุบันไม่สอดคล้องในเรื่องนั้น) มีความแตกต่างในการที่sortจะใช้ขั้นตอนวิธีการเรียงที่เกิดเหตุของการเปรียบเทียบสตริง (โดยปกติจะใช้strcoll()เพื่อเปรียบเทียบสตริง) ในขณะที่uniqการตรวจสอบตัวตนไบต์มูลค่า (โดยปกติจะใช้strcmp()) .

เรื่องนี้มีเหตุผลอย่างน้อยสองประการ

  • ในบางแห่งโดยเฉพาะอย่างยิ่งในระบบ GNU มีอักขระต่าง ๆ เรียงกัน ตัวอย่างเช่นในโลแคล en_US.UTF-8 บนระบบ GNU อักขระ①②③④⑤⑥⑦⑧⑨⑩ ... ทั้งหมดและอื่น ๆ อีกมากมายเรียงลำดับเดียวกันเพราะลำดับการเรียงลำดับไม่ได้ถูกกำหนดไว้ ตัวเลขอารบิก 0123456789 นั้นเรียงลำดับเหมือนกับเลขอารบิคอาหรับตะวันออก (Arabic )

    สำหรับsort -u, orts เหมือนกับ as และ 0123 เหมือนกับ ٠١٢٣ ดังนั้นsort -uจะเก็บไว้เพียงอันเดียวในขณะที่สำหรับuniq(ไม่ใช่ GNU uniqที่ใช้strcoll()(ยกเว้นด้วย-i)), ①แตกต่างจาก②และ 0123 แตกต่างจาก ٠١٢٣ ดังนั้นuniqจะพิจารณาทั้งหมด 4 ที่ไม่ซ้ำกัน

  • strcollสามารถเปรียบเทียบสตริงของอักขระที่ถูกต้องเท่านั้น (พฤติกรรมไม่ได้กำหนดตาม POSIX เมื่ออินพุตมีลำดับของไบต์ที่ไม่ได้สร้างอักขระที่ถูกต้อง) ในขณะที่strcmp()ไม่สนใจอักขระเนื่องจากการเปรียบเทียบแบบไบต์ต่อไบต์เท่านั้น นั่นคือเหตุผลอื่นว่าทำไมsort -uอาจไม่ให้ทุกบรรทัดที่ไม่ซ้ำกันหากบางอันไม่เป็นข้อความที่ถูกต้อง sort|uniqในขณะที่ยังไม่ได้ระบุในการป้อนข้อความที่ไม่ใช่ข้อความในทางปฏิบัติมีแนวโน้มที่จะให้คุณบรรทัดที่ไม่ซ้ำกันด้วยเหตุผลนั้น

ข้างรายละเอียดปลีกย่อยเหล่านั้นสิ่งหนึ่งที่ยังไม่ได้รับการบันทึกไว้เพื่อให้ห่างไกลคือuniqเปรียบเทียบสายทั้ง lexically ขณะที่sort's -uเปรียบเทียบตามข้อกำหนดการจัดเรียงที่กำหนดในบรรทัดคำสั่ง

$ 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

9

ฉันชอบที่จะใช้sort | uniqเพราะเมื่อฉันพยายามที่จะใช้-uตัวเลือก (กำจัดรายการที่ซ้ำกัน) เพื่อลบรายการที่ซ้ำกันที่เกี่ยวข้องกับสตริงตัวพิมพ์เล็กมันไม่ง่ายที่จะเข้าใจผลลัพธ์

หมายเหตุ: ก่อนที่คุณจะสามารถเรียกใช้ตัวอย่างด้านล่างนี้คุณจะต้องจำลองลำดับการเรียงมาตรฐาน C โดยทำดังต่อไปนี้:

LC_ALL=C
export LC_ALL

ตัวอย่างเช่นถ้าฉันต้องการเรียงลำดับไฟล์และลบรายการที่ซ้ำกันในขณะที่ในเวลาเดียวกันการรักษากรณีที่แตกต่างกันของสตริงที่แตกต่างกัน

$ 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?)

ความสับสนนี้แก้ไขได้โดยไม่ใช้-uตัวเลือกในการลบข้อมูลที่ซ้ำกัน การใช้uniqสามารถคาดการณ์ได้มากขึ้น ด้านล่างแรกเรียงลำดับและละเว้นกรณีและจากนั้นส่งผ่านไปuniqยังเพื่อลบรายการที่ซ้ำกัน

$ sort -f short | uniq
Apple
apple
Pear
pear

2
-uตัวเลือกของการsortส่งออกครั้งแรกของการทำงานเท่ากัน (ดูหน้าคน) ดังนั้นจะsort -fuเกิดขึ้นครั้งแรกของทุกกรณีที่ไม่สำคัญ ตรรกะที่sortใช้เพื่อลบรายการที่ซ้ำกันสามารถคาดการณ์ได้
pallxk

3

ความแตกต่างอีกอย่างที่ฉันพบในวันนี้คือเมื่อเรียงลำดับตามขอบเขตที่sort -uใช้ค่าสถานะเฉพาะกับคอลัมน์ที่คุณเรียงลำดับด้วย

$ 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

นี่ถูกกล่าวถึงในคำตอบจากStéphane Chazelas แต่ฉันชอบตัวอย่างของคุณดังนั้น +1
roaima

ขอบคุณสำหรับการชี้ให้เห็น @roaima มันไม่ชัดเจนมากในคำตอบนั้น
Stefanos Chrs
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.