¿Cómo buscar texto en un archivo ignorando nuevas líneas?

11

Me gustaría buscar texto que se pueda dividir en varias líneas en un archivo. Un grep que ignoraría los saltos de línea y devolvería el intervalo de líneas correspondiente.

por ejemplo, estaría buscando is an example filey espero que se encuentre en el siguiente archivo:

Este es
un
archivo de ejemplo.

No depender de espacios iniciales o finales, ignorar por completo todas las formas de espacio en blanco podría ser lo mejor (idealmente, tratar cualquier secuencia de espacio en blanco como un solo espacio).


Una solución no ideal es tr '\n' ' ' | grepque discrimina entre coincidencias y no coincidencias, pero no muestra la coincidencia ni trata bien los archivos grandes.

Nikana Reklawyks
fuente
en SO (sin respuesta definitiva): stackoverflow.com/q/1858312/1449460
Nikana Reklawyks
Como nota al margen, la búsqueda de emacs parece hacer el trabajo ( isearch-forward)
Nikana Reklawyks
Lo mismo ocurre con Vim de: /This\_sis. Para más detalles: :help \_s.
lcd047
Agregue esta línea al final de su línea de búsqueda: tr -n "\ n" Esto eliminará todas las líneas nuevas. ¡Espero que esto ayude!
Dan Howel

Respuestas:

12

GNU greppuede hacerlo

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

Para cumplir algunos puntos que surgen en los comentarios, hay algunas modificaciones al script:

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

Con respecto a los archivos de gran tamaño, no tengo imaginación para limitar la memoria, pero en caso de problemas, puede usarlos libremente sed

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

que mantienen no más de 4 líneas (porque 4 palabras en el patrón) en la memoria ( \(\n.*\)\{3\}).

Costas
fuente
55
Como estoy seguro de que sabe, la -zopción le dice grepque trate las nuevas líneas como caracteres de texto ordinarios y busque bytes nulos para separar los registros. En un archivo de texto sin bytes nulos (es decir, el caso típico), grep -ztratará todo el archivo como una línea. Entonces (1) esto plantea la pregunta de qué tan bien puede manejar archivos grandes, y (2) si encuentra una coincidencia, escribirá todo el archivo, sin dar pistas sobre la ubicación de la coincidencia. Además (3) el OP dijo: "idealmente, tratar cualquier secuencia de espacio en blanco como un solo espacio", por lo que debe usar \s+y agregar -E.
G-Man dice 'Reincorporar a Monica'
1
@ G-Man Gracias por tu comentario. Por favor, vea la respuesta editada.
Costas
1
(0) Ah -o; Me sigo olvidando de eso. Manera inteligente de usarlo. (1) grepComienza su nueva respuesta ^[\n]*; eso es un error tipográfico para [^\n]*. (2) dije \s+deliberadamente.  be\s*littlecoincidirá belittley care\s*lesscoincidirá careless. Pero supongo que es un problema menor. Y, si usted no desea utilizar -E, puede utilizar “la versión del hombre pobre” de \s+, a saber, \s\s*. (3) Buen sedcomando. Puede fallar si hay líneas en blanco (por lo que la frase de cuatro palabras puede extenderse en más de cuatro líneas); Pude arreglar eso agregando s/\n\s*\n/\n/.
G-Man dice 'reinstalar a Monica'
@ G-Man Gracias de nuevo. Tus comentarios son muy útiles. Intenté publicar un código más o menos portátil porque los miembros famosos siempre me presionan para que lo haga. De todos modos, incluso sin -Eti acero capaz de usar +en \s\+forma. Las líneas vacías dentro del patrón parecen ser artificiales.
Costas
Estaba pensando en documentos de texto paginados, como RFC , ISTR en el que las páginas de manual se ven así en algunos sistemas (o lo hicieron ), pero, pensándolo mejor, se me ocurre que la mayoría de esos documentos tienen encabezados o pies de página (s) que tendrían que ser eliminados antes de que puedan esperarles grepfrases.
G-Man dice 'Restablecer a Monica'
7

Prueba esto:

pcregrep -M '\bThis\s+is\b' <<EOT
This
is
an example
file.
EOT
lcd047
fuente
¿Tengo que escribir \s5 veces si busco "este es un patrón muy largo"?
Nikana Reklawyks
1
Sí: el punto \scorresponde a espacios, y la nueva línea es un "espacio".
lcd047
Quiero decir, qué pasa si el archivo es This\nis a very\nlong pattern, y no sé dónde pueden ocurrir los saltos de línea. Tendría que buscar This\sis\sa\svery\slong\spattern, ¿verdad? (que se vuelve tedioso a medida que aumenta la longitud del patrón o se pega desde otro lugar)
Nikana Reklawyks
2
Entonces lo haces de esta manera: pcregrep -M "$( echo 'This is a very long pattern' | sed 's/ /\\s+/g' )" file.
lcd047