grep บล็อกเส้นที่แน่นอน (เนื้อหาของ file1) จาก file2


9

ฉันมีสองไฟล์file1และfile2.

เนื้อหาตัวอย่างของfile1คือ:

A B
C D
E F
G H

และเนื้อหาของfile2เป็นเช่น:

A B
few other lines
E F
few more other lines
A B
C D
E F
G H
few more other lines
G H

ดังนั้นฉันต้องการค้นหาบล็อกทั้งหมดของfile1เนื้อหาในfile2เท่านั้น ซึ่งหมายความว่าผลลัพธ์ควรมีเพียงบรรทัดเหล่านี้:

A B
C D
E F
G H

โปรดทราบว่า: - เฉพาะบรรทัดที่มารวมกันควรเป็นส่วนหนึ่งของผลลัพธ์


ฉันไม่ได้รับคำถามของคุณ ถ้าคุณเพียงต้องการพิมพ์เนื้อหาที่แน่นอนของและไม่มีอะไรอื่นใช้เพียงfile1 cat file1
Wildcard

@Wildcard เขาต้องการดูว่า file2 มีเนื้อหาเหมือนกับ file1 ทั้งหมดหรือไม่ ลองคิดดูราวกับว่ากำลังมองหาบทที่เฉพาะเจาะจงในหนังสือ
Sergiy Kolodyazhnyy

ฉันลงคะแนนให้เปิดใหม่อีกครั้งเนื่องจาก "ชุดสมาชิก" ประกอบด้วยหลายบรรทัด (ฉันไม่เห็นในตอนแรก) ซึ่งซับซ้อนกว่าบรรทัดเดียวเล็กน้อยซึ่งจัดการโดยคำตอบที่ยอมรับสำหรับคำถามซ้ำที่เสนอ
Kusalananda

1
มันไม่เกี่ยวกับชุด หากคุณต้องการทำเครื่องหมายว่าซ้ำกันอย่างน้อยค้นหาคำถามอื่นเกี่ยวกับหลายบรรทัด regexps
Michael Vehrs

คำตอบ:


11

grepค่อนข้างโง่เมื่อพูดถึงรูปแบบหลายบรรทัด แต่การแปลอักขระขึ้นบรรทัดใหม่ทั้งหมด\nของทั้งรูปแบบและข้อความเพื่อค้นหาเป็นอักขระ NUL \0ก่อนที่จะเปรียบเทียบจะแก้ไขได้ การแปล\0เอาต์พุตกลับ\nเป็นสิ่งที่ต้องการด้วย

นี่คือคำสั่งของคุณสมมติว่าfile1มีรูปแบบที่คุณต้องการค้นหาfile2:

grep -aof <(tr '\n' '\0' < file1) <(tr '\n' '\0' < file2) | tr '\0' '\n'

เอาต์พุตตัวอย่างสำหรับไฟล์ที่คุณกำหนด:

A B
C D
E F
G H

คำอธิบาย:

  • <(tr '\n' '\0' < file1)สร้าง FIFO / named pipe / วัตถุเหมือนไฟล์ชั่วคราวที่เท่ากับfile1แต่มีอักขระขึ้นบรรทัดใหม่ทั้งหมดที่แปลเป็นอักขระ NUL
  • <(tr '\n' '\0' < file2)ไม่เหมือนกัน file2แต่สำหรับ
  • grep -f PATTERN_FILE INPUT_FILEการค้นหารูปแบบ (s) จากในPATTERN_FILEINPUT_FILE
  • -aธงgrepช่วยให้การจับคู่กับไฟล์ไบนารี \0นี้เป็นสิ่งจำเป็นเพราะมิฉะนั้นก็จะข้ามไฟล์ที่มีอักขระที่ไม่สามารถพิมพ์เช่น
  • -oธงชาติgrepทำให้พิมพ์เฉพาะลำดับการจับคู่ไม่ได้เป็นสายทั้งที่จะได้รับการค้นพบ
  • | tr '\0' '\n' แปลอักขระ NUL ทั้งหมดจากเอาต์พุตของคำสั่งทางด้านซ้ายกลับเป็นอักขระบรรทัดใหม่


3

เพียงเพื่อความสนุกในการทุบตีบริสุทธิ์

mapfile -t <file1
while read line ; do
    [ "$line" = "${MAPFILE[i++]}" ] || { ["$line" = "$MAPFILE" ] && i=1 || i=0; }
    [ $i -eq ${#MAPFILE[*]} ] && { printf "%s\n" "${MAPFILE[@]}"; i=0; }
done <file2

3

นี่คือบิตที่สวยงามยิ่งขึ้นgrep+ perl:

$ grep -Pzo "$(perl -pe 's/\n/\\n/g' file1.txt )"  file2.txt                    
A B
C D
E F
G H

อย่างไรก็ตามมีการจับใหญ่หนึ่งอย่าง หากมีการขึ้นบรรทัดใหม่file1ตามมารูปแบบจะไม่ถูกต้องกล่าวอีกนัยหนึ่ง: A B\nC D\nE F\nG H\n\n.

(ขอขอบคุณเป็นพิเศษ @terdon สำหรับการจัดหาส่วนของ perl)

ตามที่ระบุไว้ใน costas หนึ่งสามารถใช้perl -0pe 's/\n(\n+$)?/\\n/g' แทนperlคำสั่งอื่นเพื่อหลีกเลี่ยงการขึ้นบรรทัดใหม่ในfile1.txt


1
perl -0pe 's/\n(\n+$)?/\\n/g'หากมีการขึ้นบรรทัดใหม่และที่ไม่ได้ต้องการที่จะหา OP หากไม่มี-0ตัวgปรับแต่ง regex จะพิเศษ
Costas

1

ฉันไม่แน่ใจว่าสิ่งที่คุณต้องการจะส่งออก แต่มันเป็นเรื่องง่ายที่จะทำกับภาษาที่ไม่ได้มุ่งเน้นสายเฉพาะ (โดยเฉพาะถ้าไฟล์ทั้งสองสามารถอ่านในหน่วยความจำ) นี่คือสคริปต์หลามที่จะบอกคุณว่ามีการแข่งขันกี่ครั้ง

import sys
find = open(sys.argv[1]).read()
hay = open(sys.argv[2]).read()
print("The text occurs", hay.count(find), "times")

คุณต้องการพิมพ์file1หลาย ๆ ครั้งตามที่ตรงกันหรือไม่ แทนที่บรรทัดสุดท้ายด้วยสิ่งนี้:

print(find * hay.count(find))

คุณสามารถแพ็คทุกอย่างไว้ในการเรียก commandline หรือนามแฝงถ้าคุณต้องการ:

python -c 'import sys; print("The text occurs", open(sys.argv[2]).read().count(open(sys.argv[1]).read()), "times")' file1 file2

1
grep -lir 'A B \n D C \n whatever' ./folder_to_search

ผลลัพธ์จะเป็นไฟล์ทั้งหมดที่มีการจับคู่ข้อความที่ตรงกัน


0

นี่เป็นอีกวิธีใช้ python (ทดสอบpython3 3.5.2โดยไม่มีการร้องเรียนpylint3 1.5.6):

""" Locate entire file contents contiguous in other file """

import sys
import re
from mmap import mmap, PROT_READ

def memmap(name):
    """ Return memoryview of readonly mmap """
    with open(name, 'rb') as file:
        return memoryview(mmap(file.fileno(), 0, access=PROT_READ))

def finder(needle, haystack):
    """ Return iterator """
    return re.compile(re.escape(needle)).finditer(haystack)

print(tuple(finder(*(memmap(name) for name in sys.argv[1:3]))))

การจัดการอาร์กิวเมนต์บรรทัดคำสั่งผ่านsys.argvทำได้ง่าย คุณสามารถทำสิ่งอื่น ๆ อีกมากมายกับค่าตอบแทนของfinderทั้งสองวัตถุที่คุณผ่านในนอกจากนี้ผ่านไปmemoryview tupleแต่ละSRE_Matchรายการให้ผลลัพธ์โดยตัววนซ้ำที่ส่งคืนโดยfinderมีวิธีการที่หลากหลายตัวอย่างที่สรุปไว้ในprintผลลัพธ์ ( spanตัวอย่างเช่นบอกช่วงไบต์ของการแข่งขันแต่ละครั้ง)

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