Как искать текст в файле, игнорируя переводы строки?

11

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

например, я буду искать is an example fileи ожидать, что он будет найден в следующем файле:

Это пример файл.

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


Одно неидеальное решение состоит в том tr '\n' ' ' | grep, что различает совпадения и несоответствия, но не показывает совпадения и не работает с большими файлами.

Никана Рекламикс
источник
на SO (
точного
Как примечание, поиск в emacs, кажется, делает свою работу ( isearch-forward)
Никана Рекламикс
Так же Вим - х: /This\_sis. Для получения более подробной информации: :help \_s.
lcd047
Добавьте эту строку в конце строки поиска: tr -n "\ n" Это удалит все новые строки. Надеюсь, это поможет!
Дэн

Ответы:

12

GNU grepможет это сделать

grep -z 'is\san\sexample\sfile.' file

Для выполнения некоторых пунктов, которые возникают в комментариях, есть некоторые модификации скрипта:

 grep -oz '^[^\n]*\bis\s*an\s*example\s*file\.[^\n]*' file

Что касается огромных файлов, я не имею представления об ограничении памяти, но в случае проблем вы можете свободно использовать sed

sed '/\bis\b/{
          :1
          N
          /file\.\|\(\n.*\)\{3\}/!b1
         }
     /\<is\s*an\s*example\s*file\./p
     D' file

которые хранят в памяти не более 4 строк (потому что в шаблоне 4 слова \(\n.*\)\{3\}).

Костас
источник
5
Как я уверен, вы знаете, что -zопция говорит, что grepнужно рассматривать новые строки как обычные текстовые символы и искать нулевые байты в отдельных записях. В текстовом файле без нулевых байтов (т.е. в типичном случае) grep -zвесь файл будет обрабатываться как одна строка. Так (1) это поднимает вопрос о том, насколько хорошо он может обрабатывать большие файлы, и (2) если он найдет совпадение, он выпишет весь файл, не давая подсказки относительно местоположения совпадения. Также (3) ФП сказал: «в идеале, обрабатывать любую последовательность пробелов как один пробел», поэтому вы должны использовать \s+и добавить -E.
G-Man говорит: «Восстановите Монику»
1
@ G-Man Спасибо за комментарий. Пожалуйста, смотрите отредактированный ответ.
Костас
1
(0) А, -o; Я продолжаю забывать об этом. Умный способ использовать его. (1) grepначинается ваш новый ответ ^[\n]*; это опечатка для [^\n]*. (2) Я сказал \s+сознательно.  be\s*littleбудет соответствовать belittle, и care\s*lessбудет соответствовать careless. Но я думаю, что это небольшая проблема. И, если вы не хотите использовать -E, вы можете использовать «версию бедного человека» из \s+, а именно \s\s*. (3) Хорошая sedкоманда. Он может потерпеть неудачу, если есть пустые строки (поэтому фраза из четырех слов может занимать более четырех строк); Я смог это исправить, добавив s/\n\s*\n/\n/.
G-Man говорит «Восстановить Монику»
@ G-Man Спасибо, что еще. Ваши комментарии очень полезны. Я пытаюсь опубликовать более или менее переносимый код, потому что известные участники каждый раз подталкивают меня к этому. Во всяком случае, даже без -Eвас сталь в состоянии использовать +в \s\+форме. Пустые линии внутри рисунка кажутся надуманными.
Костас
Я думал о разбитых на страницы текстовых документах, таких как RFC - ISTR, на которых man-страницы выглядят так же, как в некоторых системах (или делал ), - но, если подумать, мне кажется, что большинство таких документов имеют верхний или нижний колонтитулы страниц (ы), которые должны быть удалены, прежде чем вы могли бы надеяться на grepних для фраз.
G-Man говорит: «Восстановите Монику»
7

Попробуй это:

pcregrep -M '\bThis\s+is\b' <<EOT
This
is
an example
file.
EOT
lcd047
источник
Нужно ли вводить \s5 раз, если я ищу «это очень длинный шаблон»?
Никана Рекламикс
1
Да: точка \sсоответствует пробелам, а символ новой строки - это пробел.
lcd047
Я имею в виду, что если файл This\nis a very\nlong pattern, и я не знаю, где могут произойти разрывы строки. Я должен был бы искать This\sis\sa\svery\slong\spattern, верно? (который становится утомительным, когда длина рисунка увеличивается или вставляется из другого места)
Никана Рекламикс
2
Тогда вы делаете это так: pcregrep -M "$( echo 'This is a very long pattern' | sed 's/ /\\s+/g' )" file.
lcd047