Jak wyszukiwać tekst w pliku, ignorując znaki nowej linii?

11

Chciałbym wyszukać tekst, który może być podzielony na kilka wierszy w pliku. Grep, który zignoruje podział linii i zwróci pasujący zakres linii.

np. szukałbym is an example filei oczekuję, że znajdzie się w następującym pliku:

To przykładowy plik.

Nie polegać na wiodących lub końcowych spacjach, najlepiej całkowicie ignorować wszystkie formy białej przestrzeni (najlepiej traktując dowolną sekwencję białej przestrzeni jako pojedynczą spację).


Jednym nieidealnym rozwiązaniem jest tr '\n' ' ' | greprozróżnienie między dopasowaniami a niepasującymi, ale nie pokazuje dopasowania ani nie radzi sobie dobrze z dużymi plikami.

Nikana Reklawyks
źródło
w sprawie SO (brak ostatecznej odpowiedzi): stackoverflow.com/q/1858312/1449460
Nikana Reklawyks
Na marginesie: poszukiwanie emacsa wydaje się wykonywać pracę ( isearch-forward)
Nikana Reklawyks
Więc nie Vima: /This\_sis. Aby uzyskać więcej informacji: :help \_s.
lcd047,
Dodaj ten wiersz na końcu wiersza wyszukiwania: tr -n "\ n" Spowoduje to usunięcie wszystkich nowych wierszy. Mam nadzieję, że to pomoże!
Dan Howel,

Odpowiedzi:

12

GNU grepmoże to zrobić

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

Aby spełnić niektóre punkty, które pojawiają się w komentarzach, istnieją pewne modyfikacje skryptu:

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

Jeśli chodzi o ogromne pliki, nie wyobrażam sobie ograniczenia pamięci, ale w przypadku problemu możesz swobodnie korzystać sed

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

które przechowują w pamięci nie więcej niż 4 wiersze (ponieważ 4 słowa we wzorach \(\n.*\)\{3\}).

Costas
źródło
5
Jak zapewne wiesz, -zopcja mówi, grepaby traktować znaki nowej linii jak zwykłe znaki tekstowe i szukać nul bajtów do oddzielania rekordów. W pliku tekstowym bez bajtów zerowych (tj. W typowym przypadku) grep -zpotraktuje cały plik jako jedną linię. Tak więc (1) rodzi się pytanie, jak dobrze radzi sobie z dużymi plikami, i (2) jeśli znajdzie dopasowanie, wypisze cały plik, nie dając pojęcia o lokalizacji dopasowania. Również (3) OP powiedział: „idealnie, traktując dowolną sekwencję białych spacji jako pojedynczą spację”, więc powinieneś użyć \s+i dodać -E.
G-Man mówi „Przywróć Monikę”
1
@ G-Man Dziękujemy za komentarz. Zobacz edytowaną odpowiedź.
Costas
1
(0) Ah -o,; Ciągle o tym zapominam. Sprytny sposób z niego korzystać. (1) Twoja nowa grepodpowiedź zaczyna się ^[\n]*; to literówka [^\n]*. (2) powiedziałem \s+celowo.  be\s*littlebędzie pasować belittlei care\s*lessbędzie pasować careless. Ale to chyba drobny problem. A jeśli nie chcesz używać -E, możesz użyć „wersji biedaka” \s+, a mianowicie \s\s*. (3) Ładne sedpolecenie. Może się nie powieść, jeśli są puste linie (tak, aby czterosłowowa fraza mogła rozciągać się na więcej niż cztery linie); Mogłem to naprawić, dodając s/\n\s*\n/\n/.
G-Man mówi „Przywróć Monikę”
@ G-Man Dziękuję againg. Twoje komentarze są bardzo przydatne. Staram się publikować mniej lub bardziej przenośny kod, ponieważ sławni członkowie za każdym razem zachęcają mnie do tego. Zresztą nawet bez -Eciebie stali w stanie wykorzystać +w \s\+formie. Puste linie wewnątrz wzoru wydają się być wymyślone.
Costas
Myślałem o paginowanych dokumentach tekstowych, takich jak RFC - ISTR, że strony podręcznika man wyglądają tak w niektórych systemach (lub tak zrobiłem ) - ale po dalszych myślach przychodzi mi do głowy, że większość takich dokumentów ma nagłówki i / lub stopki stron Należy je rozebrać, zanim będzie można oczekiwać od grepnich wyrażeń.
G-Man mówi „Przywróć Monikę”
7

Spróbuj tego:

pcregrep -M '\bThis\s+is\b' <<EOT
This
is
an example
file.
EOT
lcd047
źródło
Czy muszę wpisywać \s5 razy, jeśli szukam „to bardzo długi wzór”?
Nikana Reklawyks
1
Tak: punkt \sodpowiada spacjom, a nowa linia to „spacja”.
lcd047,
Mam na myśli, co jeśli plik jest This\nis a very\nlong patterni nie wiem, gdzie mogą wystąpić podziały linii. Musiałbym szukać This\sis\sa\svery\slong\spattern, prawda? (co staje się nużące wraz ze wzrostem długości wzoru lub wklejeniem go z innego miejsca)
Nikana Reklawyks
2
Następnie należy zrobić to tak: pcregrep -M "$( echo 'This is a very long pattern' | sed 's/ /\\s+/g' )" file.
lcd047,