ตรวจสอบว่าไฟล์ทุกบรรทัดเกิดขึ้นในไฟล์อื่นหรือไม่


14

ฉันมีสองไฟล์: file1 ที่มีประมาณ 10,000 บรรทัดและ file2 ที่มีไม่กี่ร้อยบรรทัด ฉันต้องการตรวจสอบว่าทุกบรรทัดของ file2 เกิดขึ้นใน file1 นั่นคือ: ∀ line ℓ∈ file2: ℓ∈ file1

หากใครไม่ทราบความหมายของสัญลักษณ์เหล่านี้หรือ "ตรวจสอบว่าทุกบรรทัดของ file2 เกิดขึ้นใน file1" หมายถึง: บรรทัดที่เทียบเท่าหลายบรรทัดในไฟล์ใดไฟล์หนึ่งไม่มีผลต่อการตรวจสอบที่ส่งคืนว่าไฟล์นั้นตรงตามข้อกำหนดหรือไม่

ฉันจะทำสิ่งนี้ได้อย่างไร


2
ไฟล์เหล่านั้นอาจมีสายซ้ำกันหรือไม่ หากfile2มี 2 ​​บรรทัดAคุณต้องfile1มีอย่างน้อย 2 บรรทัดAหรือไม่
Stéphane Chazelas

2
@ StéphaneChazelasทุกบรรทัด (ทั้งไฟล์) รับประกันว่าจะไม่ซ้ำกัน
UTF-8

1
@ UTF-8 นั่นจะเป็นรายละเอียดที่สำคัญในการแก้ไขคำถามของคุณ
David Z

2
@DavidZ ไม่ได้อีกต่อไปแล้วเนื่องจากคำตอบที่มีอยู่ไม่ได้รับประกัน ดังนั้นโดยการแก้ไขคำถามตอนนี้ฉันจะลดขอบเขตของคำตอบที่ชัดเจน
UTF-8

@ UTF-8 ฉันคิดว่าเป็นเช่นนั้นแม้ว่าคำถามจะคลุมเครือเล็กน้อยหากไม่มีเช่นหากบรรทัดที่กำหนดเกิดขึ้น 5 ครั้งใน file2 บรรทัดนั้นจะต้องเกิดขึ้น 5 ครั้งใน file1 (เมื่อเทียบกับเพียงครั้งเดียว)? หากคุณมีข้อกำหนดดังกล่าวดูเหมือนว่าคำตอบที่มีอยู่จะไม่ทำงานดังนั้นฉันขอแนะนำอย่างน้อยการแก้ไขในสิ่งที่ทำให้ชัดเจนว่านั่นไม่ใช่สิ่งที่คุณหมายถึง
David Z

คำตอบ:


18
comm -13 <(sort -u file_1) <(sort -u file_2)

file_2คำสั่งนี้พระทัยสายออกที่ไม่ซ้ำกับ ดังนั้นถ้าเอาท์พุทเป็นที่ว่างเปล่าแล้วทุกเส้นมีอยู่ในfile_2file_1

จากคนของ comm:

   With  no  options,  produce  three-column  output.  Column one contains
   lines unique to FILE1, column two contains lines unique to  FILE2,  and
   column three contains lines common to both files.

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

@don_crissti True คงที่: -uตัวเลือกที่เพิ่มให้กับsortคำสั่ง ตอนนี้บรรทัดที่ไม่ซ้ำกันเท่านั้นที่เหลืออยู่ในไฟล์ทั้งสองเรียง
MiniMax

ทางออกที่ยอดเยี่ยมจริงๆ! ไวยากรณ์นี้ใช้กับโปรแกรมใด ๆ ที่คาดว่าไฟล์หรือไม่ ฉันมักจะคิดว่า<piped เป็น stdin คำว่าวงเล็บเปลี่ยนหรือไม่?
UTF-8

2
@ UTF-8 มันถูกเรียกว่าเปลี่ยนตัวกระบวนการ คุณสามารถอ่านเกี่ยวกับเรื่องนี้ได้ที่นี่ และใช่มันจะทำงานเหมือนไฟล์ชั่วคราวดังนั้นจึงสามารถใช้แทนไฟล์จริงในโปรแกรมใดก็ได้ที่ต้องการไฟล์
MiniMax

หากนี่คือสิ่งที่คุณทำบ่อยครั้งคุณอาจต้องการจัดเก็บfile_1ในรูปแบบที่กำหนดไว้ล่วงหน้า บันทึกทั้งการพิมพ์และเวลา
เฮมเมอร์

7
@minimax ความคิดเห็นดียกเว้น "any" การทดแทนกระบวนการในขณะที่วิเศษไม่สามารถใช้ได้ในทุกกรณีเพราะผลลัพธ์ "ไฟล์" เป็นสตรีมไม่ใช่ไฟล์จริง ซึ่งหมายความว่าพวกเขาจะไม่ "ค้นหา" เหมือนไฟล์ปกติและสามารถใช้ได้เฉพาะเมื่อโปรแกรมอ่านไฟล์ตามปกติตั้งแต่ต้นและไม่ใช่เมื่อโปรแกรมใช้ฟังก์ชั่นเฉพาะไฟล์บางอย่างเช่นการค้นหาจุดเฉพาะหรือ กรอกลับเพื่อเริ่มต้นใหม่ตั้งแต่ต้น มีความสุขที่โปรแกรมส่วนใหญ่อ่าน () ไฟล์ของพวกเขาดังนั้นการทดแทนกระบวนการทำงานกับโปรแกรมส่วนใหญ่ แต่ไม่ใช่โปรแกรม "ใด ๆ "
กฎหมายที่ 29

7
[ $(grep -cxFf file2 <(sort -u file1)) = $(sort -u file2 | wc -l) ] && 
  echo all there || 
  echo some missing

หากจำนวนการจับคู่จาก file2 ใน (บรรทัดที่ไม่ซ้ำกัน) file1 เท่ากับจำนวนบรรทัดที่ไม่ซ้ำกันใน file2 แสดงว่าทั้งหมดนั้นอยู่ที่นั่น มิฉะนั้นพวกเขาจะไม่


5

การใช้ GNU awkซึ่งรองรับlength(array)คุณสมบัติเฉพาะ(และawkการใช้งานบางอย่างซึ่งอาจรองรับ) และไม่จำเป็นหากไฟล์ถูกเรียงลำดับ

gawk 'FNR==NR{seen[$0];next} ($0 in seen){delete seen[$0]};
    END{print (!length(seen))?"Matched":"Not Matched"}' file2 file1

นี้คือการอ่านfile2ลงในอาร์เรย์ที่เรียกว่าseenมีคีย์เป็นสายทั้งหมดของfile2

จากนั้นอ่านfile1และสำหรับแต่ละบรรทัดหากจับคู่กับบรรทัดในอาร์เรย์ที่เห็นแล้วลบคีย์นั้น

ในตอนท้ายถ้าอาร์เรย์ว่างเปล่าหมายความว่ามีบรรทัดทั้งหมดในfile2อยู่ในfile1และจะพิมพ์Matchedมิฉะนั้นจะNot Matchedปรากฏขึ้น


เพื่อความเข้ากันได้ในทุกawkการใช้งาน

awk 'FNR==NR{seen[$0];next} ($0 in seen){delete seen[$0]};
    END{for(x in seen);print (!x)?"Matched":"Not Matched"}' file2 file1

การละเว้นบรรทัดว่าง / หรือเส้นที่มีช่องว่าง แต่ถ้าในfile2คุณจะต้องเพิ่มNFเงื่อนไขในการNR==FNR && NF {...ที่จะข้ามไปอ่านพวกเขาลงในอาร์เรย์


length(array)เป็น AFAIK ที่เพ่งเล็งเพียง มันไม่แน่นอน POSIX
dave_thompson_085

@ dave_thompson_085 ถูกต้องฉันได้อัปเดตคำตอบแล้ว ขอบคุณ
αғsнιη

3

การใช้commคุณสามารถค้นหาบรรทัดที่พบได้ทั่วไปในไฟล์ทั้งสอง

comm -12 file1 file2

ดูman commรายละเอียดเพิ่มเติมได้ที่


แก้ไขให้ถูกต้องคือส่งคืนบรรทัดทั่วไปในทั้งสองไฟล์ แต่สิ่งนี้ไม่ได้ให้คำตอบกับ OP ของ Q หากคุณมีบรรทัดใน file2 ซึ่งไม่ได้ออกใน file1 ดังนั้นทุกบรรทัดของ file2 จึงไม่มีอยู่ใน file1
αғsнιη

1
ควรจัดเรียงไฟล์ จาก man " comm- เปรียบเทียบสองไฟล์ที่เรียงลำดับทีละบรรทัด"
MiniMax

@MiniMax ถูกต้อง มันใช้งานไม่ได้ คำตอบอื่น ๆ ที่ใช้commมีคำตอบที่ไม่ถูกต้องอย่างเห็นได้ชัด เมื่อฉันเรียกใช้คำสั่งของคุณฉันได้รับคำเตือนว่าไฟล์ไม่เรียงตามลำดับและมีจำนวนบรรทัดมากซึ่งแน่นอนว่าอยู่ในทั้งสองไฟล์
UTF-8

3
diff -q <(sort -u file2) <(grep -Fxf file2 file1 | sort -u)

จะไม่สร้างเอาต์พุตหากfile1มีบรรทัดทั้งหมดที่เข้าfile2และออกด้วยสถานะ0มิฉะนั้นจะพิมพ์ออกมาเช่น

Files /proc/self/fd/11 and /proc/self/fd/12 differ

และออกด้วยสถานะ 1


2

ใช้โปรแกรม Python:

#!/usr/bin/env python3
import sys

def open_arg(path):
    return sys.stdin if path == '-' else open(path)

def strip_linebreak(s):
    return s[:-1] if s.endswith('\n') else s

with open_arg(sys.argv[1]) as pattern_file:
    patterns = set(map(strip_linebreak, pattern_file))

with open_arg(sys.argv[2]) as dataset_file:
    for l in map(strip_linebreak, dataset_file):
        patterns.remove(l)
        if not patterns:
            break

sys.exit(int(bool(patterns)))

การใช้งาน:

python3 contains-all.py file2 file1

สถานะการออกจากโปรแกรมระบุว่ารูปแบบของไฟล์ 2 ทั้งหมดตรงกันหรือไม่:

  • 0 (สำเร็จ) หมายถึงรูปแบบทั้งหมดตรงกัน
  • 1 (ล้มเหลว) หมายถึงรูปแบบบางอย่างไม่ตรงกัน

เพื่อสอบถามสถานะออกในเปลือก (สคริปต์) คุณสามารถใช้$?ตัวแปรพิเศษหรือสำนวนอื่น ๆ ที่ประเมินสถานะออกคำสั่งเช่นผู้ประกอบการลัดวงจร&&และ||และการแสดงออกเช่นเงื่อนไขหรือif whileตัวอย่าง:

if python3 compare-all.py file2 file1 && some-other --condition; then
    # do stuff
fi

1

combineจากmoreutilsจะแสดงบรรทัดทั้งหมดfile2ที่ไม่ได้อยู่ในfile1:

combine file2 not file1

จากนั้นคุณสามารถนับจำนวนบรรทัดได้โดยไปที่wc -l:

if [ $(combine file2 not file1 | wc -l) != 0 ]; then
  echo "lines missing"
else
  echo "You're fine"
fi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.