คุณสามารถทำได้โดยการควบคุมการจัดรูปแบบของบรรทัดเก่า / ใหม่ / ไม่เปลี่ยนแปลงในdiff
เอาต์พุตGNU :
diff --new-line-format="" --unchanged-line-format="" file1 file2
ไฟล์อินพุตควรถูกเรียงลำดับเพื่อให้ทำงานได้ ด้วยbash
(และzsh
) คุณสามารถเรียงลำดับแบบแทนที่ด้วยการทดแทนกระบวนการ<( )
:
diff --new-line-format="" --unchanged-line-format="" <(sort file1) <(sort file2)
ในสายใหม่และไม่เปลี่ยนแปลงข้างต้นจะถูกระงับดังนั้นการเปลี่ยนแปลงเท่านั้น(เช่นสายที่ถูกลบออกในกรณีของคุณ) จะถูกส่งออก นอกจากนี้คุณยังสามารถใช้diff
ตัวเลือกสองสามอย่างที่โซลูชันอื่นไม่เสนอเช่น-i
เพื่อละเว้นตัวพิมพ์เล็กหรือตัวเลือกช่องว่างต่าง ๆ ( -E
, -b
และ-v
อื่น ๆ ) สำหรับการจับคู่ที่เข้มงวดน้อยกว่า
คำอธิบาย
ตัวเลือก--new-line-format
, --old-line-format
และ--unchanged-line-format
ช่วยให้คุณสามารถควบคุมวิธีการdiff
รูปแบบที่แตกต่างกันคล้ายกับ printf
specifiers รูปแบบ ตัวเลือกเหล่านี้จัดรูปแบบใหม่ (เพิ่ม), เก่า (ลบ) และไม่เปลี่ยนแปลงบรรทัดตามลำดับ การตั้งค่าหนึ่งให้ว่าง "" ป้องกันการแสดงผลของบรรทัดประเภทนั้น
หากคุณคุ้นเคยกับรูปแบบdiffแบบรวมคุณสามารถสร้างใหม่ได้บางส่วนด้วย:
diff --old-line-format="-%L" --unchanged-line-format=" %L" \
--new-line-format="+%L" file1 file2
ตัว%L
ระบุเป็นบรรทัดที่มีปัญหาและเรานำหน้าแต่ละคำด้วย "+" "-" หรือ "" เช่นdiff -u
(โปรดทราบว่ามันจะให้ผลลัพธ์ที่แตกต่างเท่านั้นมันขาด---
+++
และ@@
บรรทัดที่ด้านบนของการเปลี่ยนแปลงที่จัดกลุ่มไว้แต่ละรายการ) นอกจากนี้คุณยังสามารถใช้ในการทำสิ่งที่มีประโยชน์อื่น ๆ เช่นจำนวนแต่ละบรรทัด%dn
ด้วย
diff
วิธี (พร้อมกับคำแนะนำอื่น ๆcomm
และjoin
) เพียง แต่ผลิตการส่งออกที่คาดว่าจะมีการจัดเรียงการป้อนข้อมูลแม้ว่าคุณจะสามารถใช้<(sort ...)
ในการจัดเรียงในสถานที่ ต่อไปนี้เป็นawk
สคริปต์ (nawk) แบบง่าย ๆ(ได้รับแรงบันดาลใจจากสคริปต์ที่ลิงก์ไปยังในคำตอบของ Konsolebox) ซึ่งยอมรับไฟล์อินพุตที่ได้รับคำสั่งตามอำเภอใจและเอาต์พุตบรรทัดที่ขาดหายไปตามลำดับที่เกิดขึ้นใน
# output lines in file1 that are not in file2
BEGIN { FS="" } # preserve whitespace
(NR==FNR) { ll1[FNR]=$0; nl1=FNR; } # file1, index by lineno
(NR!=FNR) { ss2[$0]++; } # file2, index by string
END {
for (ll=1; ll<=nl1; ll++) if (!(ll1[ll] in ss2)) print ll1[ll]
}
ร้านค้านี้เนื้อหาทั้งหมดของ file1 ละบรรทัดเป็นเส้นจำนวนอาร์เรย์จัดทำดัชนีll1[]
และเนื้อหาทั้งหมดของ file2 ss2[]
ละบรรทัดเป็นเส้นเนื้อหาการจัดทำดัชนีอาเรย์ หลังจากอ่านไฟล์ทั้งสองแล้วให้วนซ้ำll1
และใช้in
โอเปอเรเตอร์เพื่อตรวจสอบว่ามีบรรทัดใน file1 อยู่ใน file2 หรือไม่ (สิ่งนี้จะมีเอาท์พุทที่แตกต่างกันกับdiff
วิธีการถ้ามีซ้ำกัน)
ในกรณีที่ไฟล์มีขนาดใหญ่พอที่จัดเก็บทั้งคู่ทำให้เกิดปัญหาหน่วยความจำคุณสามารถแลกเปลี่ยน CPU สำหรับหน่วยความจำได้โดยการจัดเก็บเฉพาะไฟล์ 1 และการลบการจับคู่ไปพร้อมกันตามที่อ่านไฟล์ 2
BEGIN { FS="" }
(NR==FNR) { # file1, index by lineno and string
ll1[FNR]=$0; ss1[$0]=FNR; nl1=FNR;
}
(NR!=FNR) { # file2
if ($0 in ss1) { delete ll1[ss1[$0]]; delete ss1[$0]; }
}
END {
for (ll=1; ll<=nl1; ll++) if (ll in ll1) print ll1[ll]
}
ด้านบนจัดเก็บเนื้อหาทั้งหมดของ file1 ในสองอาร์เรย์หนึ่งรายการที่จัดทำดัชนีโดยหมายเลขบรรทัดll1[]
หนึ่งรายการที่จัดทำดัชนีตามเนื้อหาss1[]
รายการ แล้วเป็น file2 จะอ่านแต่ละบรรทัดจับคู่ถูกลบออกจากและll1[]
ss1[]
ในตอนท้ายบรรทัดที่เหลือจาก file1 จะถูกส่งออกรักษาคำสั่งเดิม
ในกรณีนี้ด้วยปัญหาตามที่ระบุไว้คุณสามารถแบ่งและพิชิตโดยใช้ GNU split
(การกรองเป็นส่วนขยาย GNU) เรียกใช้ซ้ำด้วยชิ้นส่วนของไฟล์ 1 และอ่านไฟล์ 2 ทุกครั้ง:
split -l 20000 --filter='gawk -f linesnotin.awk - file2' < file1
สังเกตการใช้งานและการจัดวาง-
ความหมายstdin
ในgawk
บรรทัดคำสั่ง สิ่งนี้จัดทำโดยsplit
จาก file1 เป็นชิ้นละ 20,000 บรรทัดต่อการเรียกใช้
สำหรับผู้ใช้ในระบบที่ไม่ GNU มีเกือบแน่นอน coreutils GNU แพคเกจคุณสามารถได้รับรวมทั้งใน OSX เป็นส่วนหนึ่งของแอปเปิ้ล Xcodeเครื่องมือซึ่งมี GNU diff
, awk
แต่เพียง POSIX / BSD split
มากกว่ารุ่น GNU
awk 'NR==FNR{a[$0];next}!($0 in a)' file2 file1 > out.txt