Como procurar texto em um arquivo ignorando novas linhas?

11

Gostaria de procurar texto que possa ser dividido em várias linhas em um arquivo. Um grep que ignoraria quebras de linha e retornaria o intervalo de linhas correspondente.

por exemplo, eu estaria procurando is an example filee espero que seja encontrado no seguinte arquivo:

Este é
um
arquivo de exemplo.

Para não depender de espaços iniciais ou finais, ignorar completamente todas as formas de espaço em branco pode ser o melhor (idealmente, tratar qualquer sequência de espaço em branco como um espaço único).


Uma solução não ideal é tr '\n' ' ' | grep, que discrimina entre correspondências e não correspondências, mas não mostra a correspondência nem lida bem com arquivos grandes.

Nikana Reklawyks
fonte
no SO (sem resposta definitiva): stackoverflow.com/q/1858312/1449460 #
Nikana Reklawyks
Como uma nota lateral, pesquisa emacs parece fazer o trabalho ( isearch-forward)
Nikana Reklawyks
O mesmo acontece com Vim de: /This\_sis. Para mais detalhes: :help \_s.
Lcd047 18/05
Adicione esta linha no final da sua linha de pesquisa: tr -n "\ n" Isso removerá todas as novas linhas. Espero que esta ajuda!
Dan Howel

Respostas:

12

O GNU greppode fazer isso

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

Para preencher alguns pontos que surgem nos comentários, existem algumas modificações no script:

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

Em relação a arquivos grandes, não tenho imaginação para limitar a memória, mas no caso de problemas, você é livre para usar sed

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

que mantêm não mais que 4 linhas (porque 4 palavras no padrão) na memória ( \(\n.*\)\{3\}).

Costas
fonte
5
Como eu tenho certeza que você sabe, a -zopção diz greppara tratar as novas linhas como caracteres de texto comuns e procurar nul bytes para separar registros. Em um arquivo de texto sem bytes nulos (isto é, o caso típico), grep -zo arquivo inteiro será tratado como uma linha. Portanto, (1) isso levanta a questão de quão bem ele pode lidar com arquivos grandes e (2) se encontrar uma correspondência, ela escreverá o arquivo inteiro, sem nenhuma pista sobre a localização da correspondência. Além disso (3), o OP disse: “idealmente, tratando qualquer sequência de espaço em branco como um espaço único”; portanto, você deve usar \s+e adicionar -E.
G-Man diz 'Reinstate Monica'
1
@ G-Man Obrigado por comentar. Por favor, veja a resposta editada.
Costas
1
(0) Ah -o; Eu continuo esquecendo disso. Maneira inteligente de usá-lo. (1) Sua nova grepresposta começa ^[\n]*; isso é um erro de digitação [^\n]*. (2) eu disse \s+deliberadamente.  be\s*littleirá corresponder belittlee care\s*lessirá corresponder careless. Mas acho que esse é um problema menor. E, se você não quiser usar -E, poderá usar a "versão do pobre homem" de \s+, a saber \s\s*,. (3) bom sedcomando. Pode falhar se houver linhas em branco (portanto, a frase de quatro palavras pode se espalhar por mais de quatro linhas); Consegui consertar isso adicionando s/\n\s*\n/\n/.
G-Man diz 'Restabelecer Monica'
@ G-Man Obrigado de novo. Seus comentários são muito úteis. Eu tentei postar código mais ou menos portátil, porque membros famosos sempre me pressionam a fazê-lo. De qualquer forma, mesmo sem -Evocê, o aço pode ser usado +em \s\+forma. Linhas vazias dentro do padrão parecem ser artificial.
Costas
Eu estava pensando em documentos de texto paginados, como RFCs - ISTR que as páginas homem parecido com que em alguns sistemas (ou fez ) - mas, ainda pensamento, ocorre-me que a maioria desses documentos têm topo da página (s) e / ou rodapé (s) que precisariam ser removidos antes que você pudesse esperar grepfrases.
G-Man diz 'Reinstate Monica'
7

Tente o seguinte:

pcregrep -M '\bThis\s+is\b' <<EOT
This
is
an example
file.
EOT
lcd047
fonte
Preciso digitar \s5 vezes se procurar por "este é um padrão muito longo"?
Nikana Reklawyks
1
Sim: o ponto \scorresponde a espaços e a nova linha é um "espaço".
Lcd047 18/05
Quero dizer, e se o arquivo estiver This\nis a very\nlong pattern, e não sei onde as quebras de linha podem ocorrer. Eu teria que procurar This\sis\sa\svery\slong\spattern, certo? (que se torna fastidioso como o comprimento do padrão aumenta ou é colado a partir de outro local)
Nikana Reklawyks
2
Então você fazê-lo como este: pcregrep -M "$( echo 'This is a very long pattern' | sed 's/ /\\s+/g' )" file.
Lcd047 18/05