ฉันต้องการเปรียบเทียบ file1 กับ file2 และสร้าง file3 ซึ่งมีบรรทัดใน file1 ซึ่งไม่มีอยู่ใน file2
ฉันต้องการเปรียบเทียบ file1 กับ file2 และสร้าง file3 ซึ่งมีบรรทัดใน file1 ซึ่งไม่มีอยู่ใน file2
คำตอบ:
diff (1) ไม่ใช่คำตอบ แต่ comm (1) คือ
NAME
comm - compare two sorted files line by line
SYNOPSIS
comm [OPTION]... FILE1 FILE2
...
-1 suppress lines unique to FILE1
-2 suppress lines unique to FILE2
-3 suppress lines that appear in both files
ดังนั้น
comm -2 -3 file1 file2 > file3
ต้องเรียงไฟล์อินพุต ถ้าไม่ใช่ให้เรียงลำดับก่อน สามารถทำได้ด้วยไฟล์ชั่วคราวหรือ ...
comm -2 -3 <(sort file1) <(sort file2) > file3
โดยมีเงื่อนไขว่าเชลล์ของคุณรองรับการทดแทนกระบวนการ (bash does)
comm -23
ยูทิลิตี้ Unix diff
มีไว้เพื่อจุดประสงค์นี้
$ diff -u file1 file2 > file3
ดูคู่มือและอินเทอร์เน็ตสำหรับตัวเลือกรูปแบบเอาต์พุตต่างๆ ฯลฯ
พิจารณาสิ่งนี้:
ไฟล์ a.txt:
abcd
efgh
ไฟล์ b.txt:
abcd
คุณสามารถพบความแตกต่างด้วย:
diff -a --suppress-common-lines -y a.txt b.txt
ผลลัพธ์จะเป็น:
efgh
คุณสามารถกำหนดผลลัพธ์ใหม่ในไฟล์เอาต์พุต (c.txt) โดยใช้:
diff -a --suppress-common-lines -y a.txt b.txt > c.txt
สิ่งนี้จะตอบคำถามของคุณ:
"... ซึ่งมีบรรทัดใน file1 ซึ่งไม่มีอยู่ใน file2"
-d
ด้วยซึ่งจะdiff
พยายามอย่างเต็มที่เพื่อค้นหาความแตกต่างที่น้อยที่สุดเท่าที่จะเป็นไปได้ -i
, -E
, -w
, -B
และ--suppress-blank-empty
ยังสามารถเป็นประโยชน์บางครั้งแม้จะไม่ได้เสมอ หากคุณไม่ทราบว่าอะไรเหมาะกับกรณีการใช้งานของคุณให้ลองdiff --help
ก่อน (ซึ่งโดยทั่วไปเป็นความคิดที่ดีเมื่อคุณไม่รู้ว่าคำสั่งสามารถทำอะไรได้บ้าง)
บางครั้งdiff
ก็เป็นยูทิลิตี้ที่คุณต้องการ แต่บางครั้งjoin
ก็เหมาะสมกว่า ไฟล์ต้องได้รับการจัดเรียงไว้ล่วงหน้าหรือหากคุณใช้เชลล์ที่รองรับการทดแทนกระบวนการเช่น bash, ksh หรือ zsh คุณสามารถจัดเรียงได้ทันที
join -v 1 <(sort file1) <(sort file2)
ลอง
sdiff file1 file2
โดยปกติแล้วจะได้ผลดีกว่าสำหรับฉันมาก คุณอาจต้องการจัดเรียงไฟล์ก่อนหากลำดับของบรรทัดไม่สำคัญ (เช่นไฟล์กำหนดค่าข้อความบางไฟล์)
ตัวอย่างเช่น,
sdiff -w 185 file1.cfg file2.cfg
sdiff <(sort file1) <(sort file2)
)
หากคุณต้องการแก้ปัญหานี้ด้วย coreutils คำตอบที่ยอมรับนั้นดี:
comm -23 <(sort file1) <(sort file2) > file3
คุณยังสามารถใช้sd (สตรีม diff) ซึ่งไม่ต้องการการเรียงลำดับหรือการทดแทนกระบวนการและรองรับสตรีมที่ไม่มีที่สิ้นสุดเช่น:
cat file1 | sd 'cat file2' > file3
อาจจะไม่เป็นประโยชน์มากนักในตัวอย่างนี้ แต่ยังคงพิจารณาอยู่ ในบางกรณีคุณจะไม่สามารถใช้comm
หรือgrep -F
หรือไม่diff
ได้
นี่คือบล็อกโพสต์ที่ฉันเขียนเกี่ยวกับสตรีมที่แตกต่างกันบนเทอร์มินัลซึ่งแนะนำ sd
ยังไม่มีgrep
วิธีแก้ปัญหา?
บรรทัดที่มีอยู่ใน file2 เท่านั้น:
grep -Fxvf file1 file2 > file3
บรรทัดที่มีอยู่ใน file1 เท่านั้น:
grep -Fxvf file2 file1 > file3
บรรทัดที่มีอยู่ในทั้งสองไฟล์:
grep -Fxf file1 file2 > file3
มีคำตอบมากมายแล้ว แต่ไม่มีคำตอบใดที่สมบูรณ์แบบ IMHO คำตอบของ Thanatos จะมีอักขระพิเศษบางตัวต่อบรรทัดและคำตอบของ Sorpigal กำหนดให้ต้องเรียงไฟล์หรือเรียงลำดับล่วงหน้าซึ่งอาจไม่เพียงพอในทุกสถานการณ์
ฉันคิดว่าวิธีที่ดีที่สุดในการสร้างเส้นที่แตกต่างและไม่มีอะไรอื่น (ไม่มีอักขระพิเศษไม่มีการสั่งซื้อใหม่) คือการรวมกันของ diff
, grep
และawk
(หรือคล้ายกัน)
หากบรรทัดไม่มี "<" หนึ่งบรรทัดสั้น ๆ สามารถ:
diff urls.txt* | grep "<" | sed 's/< //g'
แต่นั่นจะลบทุกอินสแตนซ์ของ "<" (น้อยกว่าช่องว่าง) ออกจากบรรทัดซึ่งไม่เป็นที่ยอมรับเสมอไป (เช่นซอร์สโค้ด) ตัวเลือกที่ปลอดภัยที่สุดคือใช้ awk:
diff urls.txt* | grep "<" | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}'
ซับเดียวนี้แตกต่างทั้งสองไฟล์จากนั้นกรองเอาท์พุตสไตล์ ed ของ diff จากนั้นจึงลบ "<" ที่ต่อท้าย วิธีนี้ใช้ได้แม้ว่าบรรทัดจะมี "<" อยู่บ้าง
ฉันแปลกใจที่ไม่มีใครพูดถึงdiff -y
การสร้างเอาต์พุตแบบเคียงข้างกันเช่น:
diff -y file1 file2 > file3
และในfile3
(บรรทัดต่างๆมีสัญลักษณ์|
อยู่ตรงกลาง):
same same
diff_1 | diff_2
ใช้ยูทิลิตี้ Diff และแยกเฉพาะบรรทัดที่ขึ้นต้นด้วย <ในเอาต์พุต
diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt
ฉันลองคำตอบเกือบทั้งหมดในชุดข้อความนี้แล้ว แต่ไม่มีคำตอบใดที่สมบูรณ์ หลังจากไม่กี่เส้นทางข้างต้นได้ผลสำหรับฉัน ความแตกต่างจะทำให้คุณแตกต่าง แต่มีอักขระพิเศษที่ไม่ต้องการ โดยที่คุณเริ่มต้นเส้นความแตกต่างที่แท้จริงด้วย ">" ดังนั้นขั้นตอนต่อไปคือการgrepเส้นเริ่มต้นด้วย '>' และปฏิบัติตามโดยการลบเช่นเดียวกันกับsed
<
นอกจากนี้คุณยังจะต้องมีการปรับเปลี่ยนสายที่เริ่มต้นด้วย คุณจะเห็นสิ่งนี้หากคุณสลับลำดับของไฟล์อินพุต แม้ว่าคุณจะทำสิ่งนี้คุณก็ไม่ต้องการเว้นgrep
โดยใช้ sed เพิ่มเติม: `diff a1 a2 | sed '/> / s ///' `` ยังสามารถแบ่งบรรทัดที่มี>
หรือ<
อยู่ในสถานการณ์ที่ถูกต้องและยังคงเว้นบรรทัดพิเศษที่อธิบายหมายเลขบรรทัด diff -C0 a1 a2 | sed -ne '/^[+-] /s/^..//p'
ถ้าคุณอยากจะลองวิธีนี้เป็นวิธีที่ดีกว่าที่จะเป็น:
คุณสามารถใช้diff
กับการจัดรูปแบบผลลัพธ์ต่อไปนี้:
diff --old-line-format='' --unchanged-line-format='' file1 file2
--old-line-format=''
ปิดการใช้งานเอาต์พุตสำหรับ file1 หากบรรทัดแตกต่างกันเมื่อเปรียบเทียบใน file2
--unchanged-line-format=''
ปิดการใช้งานเอาต์พุตหากบรรทัดเหมือนกัน
หากคุณมีไฟล์ CSV ที่มีคอลัมน์เดียวหรือหลายคอลัมน์คุณสามารถดำเนินการ "diff" ทีละบรรทัดโดยใช้ฐานข้อมูลแบบฝัง sqlite3 มันมาพร้อมกับ python ดังนั้นควรมีอยู่ใน linux / mac ส่วนใหญ่ คุณสามารถเขียนสคริปต์คำสั่ง sqlite3 บน bash shell ได้โดยไม่จำเป็นต้องเขียน python
echo "
.mode csv
.import a.csv atable
.import b.csv btable
create table result as select * from atable EXCEPT select * from btable;
.output result.csv
select * from result ;
.quit
" | sqlite3 temp.db
หมายเหตุ: ตรวจสอบให้แน่ใจว่ามีการขึ้นบรรทัดใหม่สำหรับแต่ละคำสั่ง sqlite3
มันทำงานอย่างไร
หากคุณต้องการดำเนินการกับคอลัมน์เฉพาะ sqlite3 หรือ db ใด ๆ ก็เป็นวิธีที่จะไป
ฉันได้ลองใช้ไฟล์หลาย GB ที่แตกต่างกันโดยใช้เครื่องมือ diff และ comm ในตัว Sqlite เอาชนะยูทิลิตี้ linux ได้หนึ่งไมล์