grep точный блок строк (содержимое файла1) из файла2

Параметры -A и -R принимают список, разделенный запятыми.

например.

wget -r -R -l1 --no-parent -A ".dat,.haa,.hea-,.hea--,.xws,.atr,.atr-" https://www.physionet.org/physiobank/database/nsrdb/

На странице руководства

-A acclist --accept acclist

-R rejlist --reject rejlist

Укажите разделенные запятыми списки суффиксов или шаблонов имен файлов для принятия или отклонения. Обратите внимание, что если какой-либо из подстановочных знаков , *,?, [Или] появляется в элементе acclist или rejlist, он будет рассматриваться как шаблон, а не суффикс.

9
11.07.2016, 09:26
7 ответов

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' создает FIFO / именованный канал / временный файловый объект, который равен file1 , но все символы новой строки переведены в символы NUL.
  • <(tr '\ n' '\ 0' делает то же самое, но для file2 .
  • grep -f PATTERN_FILE INPUT_FILE ищет шаблоны из PATTERN_FILE в INPUT_FILE .
  • Флаг -a в grep включает сопоставление двоичных файлов. Это необходимо, потому что в противном случае будут пропущены файлы, содержащие непечатаемые символы, такие как \ 0 .
  • Флаг -o команды grep заставляет выводить только соответствующую последовательность, а не всю строку, в которой она была найдена.
  • | tr '\ 0' '\ n' переводит все символы NUL из вывода команды слева обратно в символы новой строки.
11
27.01.2020, 20:04

Вот более элегантный вариант 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)

Как заметил Костас, можно использовать perl -0pe 's / \ n (\ n + $)? / \\ n / g' вместо другой команды perl , чтобы избежать завершающей новой строки в file1.txt

3
27.01.2020, 20:04
grep -lir 'A B \n D C \n whatever' ./folder_to_search

результатом будут все файлы с точным соответствием текста

1
27.01.2020, 20:04

Вот другой подход с использованием 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, имеет множество методов, выборка которых обобщена в выводе printspan, например, указывается диапазон байт каждого совпадения).

0
27.01.2020, 20:04

Я не слишком уверен, каким вы хотите, чтобы выходные данные были, но это легко сделать с языками, которые не ориентированы исключительно на строку (особенно если оба файла могут быть прочитаны в памяти). Вот скрипт 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
27.01.2020, 20:04

Просто для удовольствия в чистом bash

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
27.01.2020, 20:04

Следующее неуклюже, но работает с GNU awk:

awk -v RS="$(<file1)" '{print RT}' file2
6
27.01.2020, 20:04

Теги

Похожие вопросы