ความแตกต่างของไฟล์ขนาดใหญ่สองไฟล์


14

ฉันมี "test1.csv" และมันมี

200,400,600,800
100,300,500,700
50,25,125,310

และ test2.csv และประกอบด้วย

100,4,2,1,7
200,400,600,800
21,22,23,24,25
50,25,125,310
50,25,700,5

ตอนนี้

diff test2.csv test1.csv > result.csv

แตกต่างจาก

diff test1.csv test2.csv > result.csv

ฉันไม่รู้ว่าคำสั่งใดถูกต้อง แต่ฉันต้องการอย่างอื่นทั้งสองคำสั่งด้านบนจะแสดงผลลัพธ์ออกมาเหมือนกัน

2 > 100,4,2,1,7
   3 2,3c3,5
   4 < 100,300,500,700
   5 < 50,25,125,310
   6 \ No newline at end of file
   7 ---
   8 > 21,22,23,24,25
   9 > 50,25,125,310

ฉันต้องการส่งออกเฉพาะความแตกต่างดังนั้น results.csv ควรมีลักษณะเช่นนี้

100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

ฉันลองdiff -qแล้วdiff -sแต่พวกเขาไม่ได้ทำเคล็ดลับ การสั่งซื้อไม่สำคัญสิ่งที่สำคัญคือฉันต้องการเห็นความแตกต่างเท่านั้นไม่มี> หรือ <หรือพื้นที่ว่างเปล่า

grep -FvF ทำเคล็ดลับในไฟล์เล็ก ๆ ไม่ใช่ไฟล์ใหญ่

ไฟล์แรกมีมากกว่า 5 ล้านบรรทัดไฟล์ที่สองมี 1300

ดังนั้น results.csv ควรส่งผลให้ ~ 4,998,700 บรรทัด

ฉันลองgrep -F -x -v -f ซึ่งไม่ได้ผล



1
@ ฉันเห็นลิงก์ของคุณและฉันเป็นสมาชิกเก่าดังนั้นฉันจึงรู้กฎ แต่ไม่ประมาทขอโทษ :) แก้ไขแล้วและฉันเห็นป๊อปอัปที่โพสต์นั้นได้รับการแก้ไขดังนั้นคุณจึงทำงานให้ฉันและฉัน ขอบคุณครับ
Lynob

50,25,125,310เป็นเรื่องปกติสำหรับไฟล์ทั้งสองไฟล์ .. คุณจำเป็นต้องลบไฟล์นั้นออกจากเอาต์พุตที่คุณต้องการ ..
heemayl

ควรรักษาลำดับไว้หรือไม่
kos

1
การเรียงลำดับของขึ้นอยู่กับสิ่งที่คุณต้องการจะทำอย่างไรกับข้อมูลที่แตกต่างกัน IMO สำหรับการทำแพทช์ ฉันมั่นใจในเครื่องมือที่ดีที่สุดของคุณ diff, grep, awk หรือ perl
Panther

คำตอบ:


20

ดูเหมือนงานสำหรับcomm:

$ comm -3 <(sort test1.csv) <(sort test2.csv)
100,300,500,700
    100,4,2,1,7
    21,22,23,24,25
    50,25,700,5

ตามที่อธิบายไว้ในman comm:

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)

ดังนั้น-3หมายความว่าเฉพาะบรรทัดที่ไม่ซ้ำกับหนึ่งในไฟล์เท่านั้นที่จะถูกพิมพ์ อย่างไรก็ตามสิ่งเหล่านั้นถูกเยื้องตามไฟล์ที่พบในการลบแท็บใช้:

$ comm -3 <(sort test1.csv) <(sort test2.csv) | tr -d '\t'
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

ในกรณีนี้คุณไม่จำเป็นต้องเรียงไฟล์และคุณสามารถทำสิ่งต่าง ๆ ให้ง่ายขึ้นเพื่อ:

comm -3 test1.csv test2.csv | tr -d '\t' > difference.csv

คุณไม่ได้ถูกหลอกโดยช่องว่างหลังจาก200,[...]บรรทัดใช่มั้ย :)
คอส

@kos ไม่ฉันจะลบช่องว่างต่อท้ายออกจากไฟล์ก่อน ฉันคิดว่าไฟล์ของ OP ไม่มีอยู่จริง
terdon

6

ใช้grepกับbashการทดแทนกระบวนการ:

$ cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv)
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

หากต้องการบันทึกผลลัพธ์เป็นresults.csv:

cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv) >results.csv
  • <()เป็นbashรูปแบบการทดแทนกระบวนการ

  • grep -vFf test2.csv test1.csv จะค้นหาบรรทัดที่ไม่ซ้ำกันเพื่อเท่านั้น test1.csv

  • grep -vFf test1.csv test2.csv จะค้นหาบรรทัดที่ไม่ซ้ำกันเพื่อเท่านั้น test2.csv

  • ในที่สุดเราก็สรุปผลโดย cat

หรือตามที่แนะนำ Oliคุณสามารถใช้การจัดกลุ่มคำสั่งด้วย:

$ { grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv; }
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

หรือเรียกใช้ทีละรายการเนื่องจากทั้งคู่เขียนถึง STDOUT พวกเขาจะได้รับการเพิ่มในที่สุด:

$ grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

1
ทำไมcatคำสั่งที่เปลี่ยนเส้นทางสองคำ ทำไมไม่เรียกใช้หนึ่งแล้วอื่น ๆ grep ... ; grep ...หรือ{ grep ... ; grep ... ; }ถ้าคุณต้องการที่จะทำบางสิ่งบางอย่างกับกลุ่มผลลัพธ์
Oli

@Oli ขอบคุณ .. นั่นเป็นความคิดที่ยอดเยี่ยม .. ฉันไม่ได้คิดอย่างนั้น ..
heemayl

4

หากลำดับของแถวไม่เกี่ยวข้องให้ใช้awkหรือperl:

awk '{seen[$0]++} END {for (i in seen) {if (seen[i] == 1) {print i}}}' 1.csv 2.csv

ใช้grepเพื่อรับบรรทัดทั่วไปและกรองออก:

grep -hxvFf <(grep -Fxf 1.csv 2.csv) 1.csv 2.csv

grep ภายในรับบรรทัดทั่วไปจากนั้น grep ภายนอกค้นหาบรรทัดที่ไม่ตรงกับบรรทัดทั่วไปเหล่านี้


คำสั่ง awk ของคุณเพิ่งใช้อีกครั้งsort | uniq -uซึ่งให้คำตอบที่ผิดเมื่อไฟล์หนึ่งไฟล์มีบรรทัดที่ซ้ำกัน สำหรับ grep ฉันจะพูดว่า "inner" / "outer" ไม่ใช่ "internal" / "external"
Peter Cordes

@PeterCordes ใช่มันเป็นเช่นนั้นและใครที่คุณจะบอกว่าเป็นผลที่ผิด?
muru

ผิดในแง่ที่ว่ามันไม่ใช่คำถามที่ถามในมุมนั้น อาจเป็นสิ่งที่ใครบางคนต้องการ แต่คุณควรชี้ให้เห็นถึงความแตกต่างระหว่างสิ่งที่คุณawkต้องการพิมพ์กับสิ่งที่comm -3และdiffคำตอบจะพิมพ์
Peter Cordes

@PeterCordes อีกครั้งคุณจะบอกว่าใคร จนกระทั่ง OP comm -3กล่าวว่านั่นคือสิ่งที่พวกเขาต้องการฉันไม่สนใจถ้าแตกต่างเอาท์พุทจากที่ ฉันไม่เห็นเหตุผลใด ๆ ว่าทำไมฉันควรอธิบายสิ่งนั้น หากคุณต้องการแก้ไขในบันทึกย่อรู้สึกฟรี
muru

OP กล่าวว่าเขาต้องการความแตกต่าง นั่นไม่ใช่สิ่งที่โปรแกรมของคุณผลิตขึ้นมาเสมอ โปรแกรมที่สร้างเอาต์พุตเดียวกันสำหรับหนึ่ง testcase แต่ไม่เป็นไปตามคำอธิบายที่เขียนสำหรับทุกกรณีต้องใช้ head up ฉันมาที่นี่เพื่อพูดอย่างนั้นและมันก็เป็นจริงโดยไม่คำนึงว่าฉันเป็นใครหรือคุณเป็นใคร ฉันเพิ่มบันทึกย่อ
Peter Cordes

4

ใช้--*-line-format=...ตัวเลือกของdiff

คุณสามารถบอกdiffสิ่งที่คุณต้องการได้ - อธิบายด้านล่าง:

diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' f1.txt f2.txt

เป็นไปได้ที่จะระบุเอาต์พุตของ diff ในวิธีที่มีรายละเอียดมากคล้ายกับprintfรูปแบบตัวเลข

บรรทัดจากไฟล์แรกtest1.csvเรียกว่าบรรทัด "เก่า" และบรรทัดจากที่สองtest2.csvเป็นบรรทัด "ใหม่" มันสมเหตุสมผลเมื่อdiffถูกใช้เพื่อดูสิ่งที่เปลี่ยนแปลงในไฟล์

ตัวเลือกที่เราต้องการคือตัวเลือกในการกำหนดรูปแบบสำหรับบรรทัด "เก่า", "ใหม่" และ "ไม่เปลี่ยนแปลง"
รูปแบบที่เราต้องการนั้นง่ายมาก:
สำหรับบรรทัดที่เปลี่ยนไปใหม่และเก่าเราต้องการแสดงเฉพาะข้อความของบรรทัด %Lเป็นสัญลักษณ์รูปแบบสำหรับข้อความบรรทัด
สำหรับบรรทัดที่ไม่เปลี่ยนแปลงเราไม่ต้องการแสดงอะไรเลย

ด้วยสิ่งนี้เราสามารถเขียนตัวเลือกเช่น--old-line-format='%L'และรวมเข้าด้วยกันโดยใช้ข้อมูลตัวอย่างของคุณ:

$ diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' test1.csv test2.csv
100,4,2,1,7
100,300,500,700
21,22,23,24,25
50,25,700,5


หมายเหตุเกี่ยวกับประสิทธิภาพ

เนื่องจากไฟล์มีขนาดแตกต่างกันลองแลกเปลี่ยนไฟล์อินพุตหากไม่สำคัญอาจเป็นไปได้ว่าการทำงานภายในdiffสามารถจัดการได้ดีกว่าวิธีอื่น ดีกว่าคือต้องการหน่วยความจำน้อยกว่าหรือคำนวณน้อยกว่า

มีตัวเลือกการปรับให้เหมาะสมสำหรับการใช้งานdiffกับไฟล์ขนาดใหญ่: --speed-large-files. มันใช้สมมติฐานเกี่ยวกับโครงสร้างไฟล์ดังนั้นจึงไม่ชัดเจนว่าจะช่วยได้ในกรณีของคุณหรือไม่ แต่ควรลองใช้ดู

ตัวเลือกรูปแบบที่อธิบายไว้ในภายใต้man diff--LTYPE-line-format=LFMT


3

เนื่องจากคำสั่งไม่จำเป็นต้องได้รับการเก็บรักษาเพียง:

sort test1.csv test2.csv | uniq -u
  • sort test1.csv test2.csv: การรวมและเรียงลำดับtest1.csvและtest2.csv
  • uniq -u: พิมพ์เฉพาะบรรทัดที่ไม่มีการซ้ำซ้อน

ไม่สามารถใช้งานได้หากไฟล์หนึ่งมีสองบรรทัดที่ไม่ปรากฏในไฟล์อื่น ทั้งสองเหตุการณ์จะเป็นdiffผลลัพธ์
Volker Siegel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.