зібрати точний блок рядків (вміст file1) з файлу2


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 він хоче перевірити, чи файл2 містить точно такий самий вміст, що і файл1. Подумайте про це так, ніби шукаєте конкретний розділ у книзі
Сергій Колодяжний

Я голосую за повторне відкриття цього питання, оскільки "встановлені члени" складаються з декількох рядків (спочатку я цього не помічав), що є дещо складнішим, ніж окремі рядки, які обробляються прийнятою відповіддю на запропонований дублікат питання.
Kusalananda

1
Йдеться не про набори. Якщо ви хочете позначити це як дублікат, принаймні знайдіть інше запитання щодо багаторядкових повторних виразів.
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 / з назвою pipe / тимчасовий файл-подібний об'єкт, що дорівнює file1, але з усіма символами нового рядка, переведеними на символи NUL.
  • <(tr '\n' '\0' < file2)робить те саме, але для file2.
  • grep -f PATTERN_FILE INPUT_FILEздійснює пошук шаблонів (и) з PATTERN_FILEв INPUT_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'. Без -0в gрегулярних виразах модифікатора є додатковим.
Костас

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

Ви можете спакувати все у виклик командного рядка чи псевдонім, якщо дуже хочете:

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наприклад, вказує діапазон байтів кожного відповідника).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.