grep blok baris yang tepat (isi file1) dari file2

9

Saya punya dua file, file1dan file2.

Isi sampel file1adalah:

A B
C D
E F
G H

dan isinya file2seperti:

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

Jadi saya ingin mencari seluruh blok file1konten file2hanya. Ini berarti output harus hanya berisi baris-baris ini:

A B
C D
E F
G H

harap dicatat bahwa: - hanya garis-garis yang menyatu, harus menjadi bagian dari output.

sachin
sumber
Saya tidak mendapatkan pertanyaan Anda. Jika Anda hanya ingin mencetak konten yang tepat file1dan tidak ada yang lain, cukup gunakan cat file1.
Wildcard
@Wildcard dia ingin melihat apakah file2 berisi konten yang persis sama dengan file1. Pikirkan tentang hal ini seolah mencari bab tertentu dalam sebuah buku
Sergiy Kolodyazhnyy
Saya memberikan suara untuk membuka kembali ini karena "anggota yang ditetapkan" terdiri dari beberapa baris (saya tidak melihatnya pada awalnya), yang sedikit lebih kompleks daripada satu baris yang ditangani oleh jawaban yang diterima untuk pertanyaan duplikat yang diajukan.
Kusalananda
1
Ini bukan tentang set. Jika Anda ingin menandai ini sebagai duplikat, setidaknya temukan pertanyaan lain tentang regexps multi-baris.
Michael Vehrs

Jawaban:

11

grepcukup bodoh ketika datang ke pola multiline, tetapi menerjemahkan semua karakter baris baru \ndari pola dan teks untuk mencari ke dalam karakter NUL \0sebelum membandingkannya memperbaikinya. Menerjemahkan \0kembali ke output \njelas juga diperlukan.

Inilah perintah Anda, dengan asumsi bahwa itu file1berisi pola yang ingin Anda cari file2:

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

Contoh output untuk file yang Anda berikan:

A B
C D
E F
G H

Penjelasan:

  • <(tr '\n' '\0' < file1)membuat FIFO / bernama pipe / objek file-like sementara yang sama file1, tetapi dengan semua karakter baris baru diterjemahkan ke karakter NUL.
  • <(tr '\n' '\0' < file2)melakukan hal yang sama, tetapi untuk file2.
  • grep -f PATTERN_FILE INPUT_FILEmencari pola dari PATTERN_FILEdalam INPUT_FILE.
  • The -abendera grepmemungkinkan pencocokan pada file biner. Ini diperlukan karena jika tidak maka akan melewatkan file yang berisi karakter yang tidak dapat dicetak seperti \0.
  • The -obendera grepmerek itu hanya mencetak urutan pencocokan, bukan seluruh baris di mana telah ditemukan.
  • | tr '\0' '\n' menerjemahkan semua karakter NUL dari output perintah di sisi kiri kembali ke karakter baris baru.
Komandan Byte
sumber
6

Berikut ini adalah canggung, tetapi bekerja dengan GNU awk:

awk -v RS="$(<file1)" '{print RT}' file2
Michael Vehrs
sumber
3

Hanya untuk bersenang-senang di bash murni

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
Costas
sumber
3

Berikut ini sedikit lebih elegan grep+ perl:

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

Namun, ada satu tangkapan besar. Jika ada baris baru Trailing di file1, pola tidak akan benar, dengan kata lain: A B\nC D\nE F\nG H\n\n.

(Terima kasih khusus @terdon untuk memberikan bagian perl)

Seperti yang dicatat oleh costas, seseorang dapat menggunakan perl -0pe 's/\n(\n+$)?/\\n/g' menggantikan perlperintah lain untuk menghindari baris baru yang tertinggal difile1.txt

Sergiy Kolodyazhnyy
sumber
1
Jika ada baris baru dan itu bukan OP yang ingin ditemukan perl -0pe 's/\n(\n+$)?/\\n/g'. Tanpa -0itu gmodifikator regex tambahan.
Costas
1

Saya tidak terlalu yakin apa yang Anda inginkan, tetapi mudah dilakukan dengan bahasa yang tidak berorientasi garis (terutama jika kedua file dapat dibaca ke dalam memori). Inilah skrip python yang akan memberi tahu Anda berapa banyak kecocokan yang ada.

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

Anda ingin mencetak file1sesering mungkin? Ganti baris terakhir dengan ini:

print(find * hay.count(find))

Anda bisa mengemas semuanya menjadi panggilan baris perintah atau alias, jika Anda benar-benar ingin:

python -c 'import sys; print("The text occurs", open(sys.argv[2]).read().count(open(sys.argv[1]).read()), "times")' file1 file2
Alexis
sumber
1
grep -lir 'A B \n D C \n whatever' ./folder_to_search

hasilnya adalah semua file dengan teks yang sama persis

meyerson
sumber
0

Berikut adalah pendekatan lain menggunakan python (diuji dengan python3 3.5.2, tanpa keluhan dari 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]))))

Penanganan argumen command line via sys.argvdiakui sederhana. Anda bisa melakukan banyak hal lain dengan nilai pengembalian finderpada dua memoryviewobjek yang Anda lewati, selain meneruskannya tuple. Setiap SRE_Matchitem yang dihasilkan oleh iterator yang dikembalikan oleh findermemiliki berbagai metode, sampel yang dirangkum dalam printoutput ( span, misalnya, memberitahu rentang byte dari setiap pertandingan).

Eirik Fuller
sumber