Как grep длинную строку через несколько строк, не зная, где находится новая строка

Я хочу найти определенную строку в нескольких строках в файле и получить строку, в которой было найдено соответствие.

однако моя проблема в том, что файл содержит одну очень длинную строку, а не, т. е. слова, и я хочу найти под-последовательность этой длинной строки. Следовательно, я не могу использовать pcregrep и просто искать word1nword2. Поскольку я действительно хочу получить номер строки, в которой было найдено совпадение, я не могу просто удалить всю новую строку письмена...

это пример того, как выглядит мой файл, я просто прописными буквами строку, чтобы вы могли найти его:

строку для поиска:

gcbcdbfceebcfhfchaaccdgfcegffgedffaeaedcbaedhacebeeebcechbcbfeeccbdhcbfg

файл для поиска в:

abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde
abcdeabcde***GCBCDBFCEEBCFHFCHAACCDGFCEGFFGEDFFAEAEDC
BAEDHACEBEEEBCECHBCBFEECCBDHCBFG***ggfbhbgcedabceedfa
fbaaechaabdbffbebecebaacfcfcdcggfchddcefbcbdegbbba

есть ли у кого-то из вас простое решение для этого?

Если нет инструмента под рукой, чтобы сделать это, я бы просто написал короткий скрипт python, чтобы сделать это, но я думаю, что любой инструмент bash будет более эффективным, чем это ...

редактировать:

большое спасибо за ваши ответы, они работают очень хорошо, если позиция символа новой строки известно.

впрочем, прошу прощения за неточность в моем вопросе. Моя проблема в том, что я не знаю, есть ли новая строка или даже более одной новой строки в строке в файле, и более того, я не знаю здесь это. Я исправил свою строку поиска, удалив новую строку, которую я невольно вставленный.

есть ли способ разрешить новую строку в любой позиции строки?

18
задан Der Hochstapler
28.11.2022 3:46 Количество просмотров материала 2435
Распечатать страницу

3 ответа

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

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

#!/usr/bin/env python
import sys

def findall_iter(S, pat):
  index = -1
  while True:
    try:
      index = S.index(pat, index+1)
      yield index
    except ValueError:
      raise StopIteration

def findall(S, pat):
  return list(findall_iter(S, pat))

# read in arguments
S = open(sys.argv[2]).read()
pattern = sys.argv[1]

# get indices of all newlines
newline_indices = findall(S, '\n')

# get psudo-indices of all pattern matches
pat_indices = findall(S.replace('\n', ''), pattern)

# iterate through each pattern match psudo-index and
# correlate it back to a real line number from the file
line_numbers = []
for pi in pat_indices:
  for i, ni in enumerate(newline_indices):
    if ni > pi+i:
      line = i + 1
      if line not in line_numbers:
        line_numbers.append(i+1)
      break

print '\n'.join(map(str, line_numbers))

плюсы:

  • если файл не слишком большой (<1 ГБ) все операции выполняются в память.
  • использует str.индексный метод для поиска подстрок вместо (медленного) регулярного выражения, соответствующего
  • понятнее, чем использование регулярных выражений

плюсы:

  • плохо работает с большими файлами.
  • создает две временные строки для выполнения задания.
  • последний for-loop трудно понять.
  • это Python (который я лично не думаю, что это con).
1
отвечен Dave 2022-11-29 11:34

Я бы сделал это с sed сценарий. Поместите это в файл, затем используйте sed -nf, чтобы запустить его.

:restart
/gcbcdbfceebcfhfchaaccdgfcegffgedffaeaedc$/{
    #   Found the first part, now discard it
    s/^.*$//
    #   Read a new line into the buffer
    N
    #   Discard the new line inserted by the N operation
    s/^\n//
    #   If next line isn't a match, start over
    /^baedhacebeeebcechbcbfeeccbdhcbfg/!b restart
    #   If it is a match, print the line number
    =
    }

вот как это выглядит, чтобы запустить его под bash. Обратите внимание, что он печатает номер строки второй строки.

bash-4.1$ cat sample.txt
abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde
abcdeabcde***gcbcdbfceebcfhfchaaccdgfcegffgedffaeaedc
baedhacebeeebcechbcbfeeccbdhcbfg***ggfbhbgcedabceedfa
fbaaechaabdbffbebecebaacfcfcdcggfchddcefbcbdegbbba
bash-4.1$
bash-4.1$ cat findmatch.sed
:restart
/gcbcdbfceebcfhfchaaccdgfcegffgedffaeaedc$/{
   #  Found the first part, now discard it
   s/^.*$//
   #  Read a new line into the buffer
   N
   #  Discard the new line inserted by the N operation
   s/^\n//
   #  If next line isn't a match, start over
   /^baedhacebeeebcechbcbfeeccbdhcbfg/!b restart
   #  If it is a match, print the line number
   =
   }
bash-4.1$
bash-4.1$ sed -nf findmatch.sed sample.txt
3
bash-4.1$
4
отвечен Nicole Hamilton 2022-11-29 13:51

Я немного смущен тем, под какими ограничениями вы работаете. Однако, если вам нужен номер строки, и grep, и pcregrep могут дать вам ala флаг-N.

$ pcregrep -nM "gcbcdbfceebcfhfchaaccdgfcegffgedffaeaedc\nbaedhacebeeebcechbcbfeeccbdhcbfg" | cut -d: -f1
2
baedhacebeeebcechbcbfeeccbdhcbfg***ggfbhbgcedabceedfa

pcregrep показывает только номер первой совпавшей строки, по-видимому, поэтому вам придется пропустить каждую другую строку вывода с sed (передайте выше sed -n 'p;N'), Если вы хотите выводить только номера строк.

3
отвечен Dave 2022-11-29 16:08

Постоянная ссылка на данную страницу: [ Скопировать ссылку | Сгенерировать QR-код ]

Ваш ответ

Опубликуйте как Гость или авторизуйтесь

Имя
Вверх