grep точный блок строк (содержимое файла1) из файла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 он хочет видеть, содержит ли file2 точно такой же контент, как file1. Думайте об этом, как будто ищите конкретную главу в книге
— Сергей Колодяжный,

Я голосую, чтобы снова открыть это, так как «набор членов» состоит из нескольких строк (я сначала этого не заметил), что несколько сложнее, чем отдельные строки, обработанные принятым ответом на предложенный дублирующий вопрос.
— Кусалананда

1
Это не о наборах. Если вы хотите пометить это как дубликат, по крайней мере, найдите другой вопрос о регулярных выражениях с несколькими строками.
— Майкл Вёрс

Ответы:


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 / именованный канал / временный файлоподобный объект, равный file1, но со всеми символами новой строки, переведенными в символы NUL.
  • <(tr '\n' '\0' < file2)делает то же самое, но для file2.
  • grep -f PATTERN_FILE INPUT_FILEищет шаблон (ы) из PATTERN_FILEin 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

Я не очень уверен, что вы хотите, чтобы вывод был, но это легко сделать с языками, которые не являются исключительно ориентированными на строки (особенно если оба файла могут быть прочитаны в память). Вот скрипт Python, который скажет вам, сколько совпадений.

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.