2009-12-07 56 views
9

¿Cómo se usa grep para generar las ocurrencias de la cadena 'export to excel' en los archivos de entrada que se detallan a continuación? Específicamente, ¿cómo manejar los saltos de línea que ocurren entre las cadenas de búsqueda? ¿Hay un cambio en grep que pueda hacer esto o algún otro comando probablemente?Cadenas de búsqueda de Grep con saltos de línea

archivos de entrada:

Archivo A.txt:

, bla, bla ... exportación a
excel ...
bla bla ..

archivo b. txt:

blah blah. .. exportación a excel ...
bla bla ..

+0

Según tengo entendido (referencia: Unix Power Tools), la familia de programas grep está orientada a la línea, lee una línea a la vez y, por lo tanto, no puede encontrar patrones en la línea. Así que puedes pensar en un script en Perl o usar sed aquí. HTH. – sateesh

+0

cómo usar sed en este contexto? –

+0

@Vijay: echo -e "foo \ nbar" | sed -n 'N;/foo \ nbar/p' – SiegeX

Respuesta

6

No sólo quiere encontrar los archivos que contienen el patrón, haciendo caso omiso de los saltos de línea, o quiere ver realmente las líneas coincidentes?

En el primer caso, se puede utilizar para convertir tr nuevas líneas de espacios:

tr '\n' ' ' | grep 'export to excel' 

Si esto último se puede hacer lo mismo, pero es posible que desee utilizar la opción -o para imprimir sólo el actual partido. Luego, querrá ajustar su expresión regular para incluir cualquier contexto adicional que desee.

+3

La solución tr + grep no es realmente adecuada para archivos grandes ya que va a formar una cadena GRANDE. – ghostdog74

0

use gawk. establece el separador de registros como excel, luego verifica "exportar a".

gawk -vRS="excel" '/export.*to/{print "found export to excel at record: "NR}' file 

o

gawk '/export.*to.*excel/{print} 
/export to/&&!/excel/{ 
    s=$0 
    getline line 
    if (line~/excel/){ 
    printf "%s\n%s\n",s,line 
    } 
}' file 
+0

¿Cómo imprimirías las líneas reales como lo haría 'grep' (para coincidencias dentro de su capacidad)? –

+0

imprimir el registro, $ 0. De lo contrario, no entiendo lo que quieres decir. – ghostdog74

+0

Creo que su edición se encarga de eso. Sin embargo, falla en algunos casos extremos. Si la entrada era algo así como "exportar Excel a \ nexcel" o "exportar a \ nalgo que no sea Excel", por ejemplo. Para responder a su pregunta en su comentario: el original de una sola línea, si $ 0 se agregaron a la salida, no mostraría el "excel" y especialmente el "..." después de eso que se indica en la pregunta del OP. –

0

He probado esto un poco y parece que funciona:

sed -n '$b; /export to excel/{p; b}; N; /export to\nexcel/{p; b}; D' filename 

Usted puede permitir un cierto espacio en blanco adicional al final y comienzo de las líneas como este:

sed -n '$b; /export to excel/{p; b}; N; /export to\s*\n\s*excel/{p; b}; D' filename 
2

No sé cómo hacer esto en grep. Revisé la página del manual para egrep(1) y tampoco puede coincidir con una línea nueva en el medio.

Me gusta la solución @Laurence Gonsalves sugirió, de usar tr(1) para eliminar las nuevas líneas. Pero como señaló, será doloroso imprimir las líneas correspondientes si lo haces de esa manera.

Si desea hacer coincidir a pesar de una nueva línea y luego imprimir la (s) línea (s) correspondiente (s), no puedo pensar en una forma de hacerlo con grep, pero no sería demasiado difícil en Python, AWK, Perl, o Ruby.

Aquí hay una secuencia de comandos de Python que resuelve el problema. Decidí que, para las líneas que solo coinciden cuando se unen a la línea anterior, imprimiría una flecha --> antes de la segunda línea del partido. Las líneas que coinciden directamente se imprimen siempre sin la flecha.

Esto se escribe suponiendo que/usr/bin/python es Python 2.x.Puede cambiar trivialmente la secuencia de comandos para trabajar en Python 3.x si así lo desea.

#!/usr/bin/python 

import re 
import sys 

s_pat = "export\s+to\s+excel" 
pat = re.compile(s_pat) 

def print_ete(fname): 
    try: 
     f = open(fname, "rt") 
    except IOError: 
     sys.stderr.write('print_ete: unable to open file "%s"\n' % fname) 
     sys.exit(2) 

    prev_line = "" 
    i_last = -10 
    for i, line in enumerate(f): 
     # is ete within current line? 
     if pat.search(line): 
      print "%s:%d: %s" % (fname, i+1, line.strip()) 
      i_last = i 
     else: 
      # construct extended line that included previous 
      # note newline is stripped 
      s = prev_line.strip("\n") + " " + line 
      # is ete within extended line? 
      if pat.search(s): 
       # matched ete in extended so want both lines printed 
       # did we print prev line? 
       if not i_last == (i - 1): 
        # no so print it now 
        print "%s:%d: %s" % (fname, i, prev_line.strip()) 
       # print cur line with special marker 
       print "--> %s:%d: %s" % (fname, i+1, line.strip()) 
       i_last = i 
     # make sure we don't match ete twice 
     prev_line = re.sub(pat, "", line) 

try: 
    if sys.argv[1] in ("-h", "--help"): 
     raise IndexError # print help 
except IndexError: 
    sys.stderr.write("print_ete <filename>\n") 
    sys.stderr.write('grep-like tool to print lines matching "%s"\n' % 
      "export to excel") 
    sys.exit(1) 

print_ete(sys.argv[1]) 

EDITAR: agregó comentarios.

Me tomé la molestia de imprimir el número de línea correcto en cada línea, usando un formato similar al que obtendría con grep -Hn.

Podría ser mucho más corto y más simple si usted no necesita los números de línea, y no te importa la lectura en todo el archivo a la vez en la memoria:

#!/usr/bin/python 

import re 
import sys 

# This pattern not compiled with re.MULTILINE on purpose. 
# We *want* the \s pattern to match a newline here so it can 
# match across multiple lines. 
# Note the match group that gathers text around ete pattern uses a character 
# class that matches anything but "\n", to grab text around ete. 
s_pat = "([^\n]*export\s+to\s+excel[^\n]*)" 
pat = re.compile(s_pat) 

def print_ete(fname): 
    try: 
     text = open(fname, "rt").read() 
    except IOError: 
     sys.stderr.write('print_ete: unable to open file "%s"\n' % fname) 
     sys.exit(2) 

    for s_match in re.findall(pat, text): 
     print s_match 

try: 
    if sys.argv[1] in ("-h", "--help"): 
     raise IndexError # print help 
except IndexError: 
    sys.stderr.write("print_ete <filename>\n") 
    sys.stderr.write('grep-like tool to print lines matching "%s"\n' % 
      "export to excel") 
    sys.exit(1) 

print_ete(sys.argv[1]) 
+0

No veo que hayas compilado la expresión regular con re.MULTILINE, entonces, ¿cómo se verifica para "sobresalir" en otra línea? – ghostdog74

+0

re.MULTILINE era * no * lo que yo quería, así que no lo especifiqué. Con re.MULTILINE, el código 're' trata una nueva línea como el final de una cadena, y no coincide después de eso. Quería una nueva línea tratada como cualquier otro espacio en blanco en la coincidencia. Agregaré algunos comentarios al código. – steveha

+0

En realidad, mi primera versión funcionaría igual con o sin re.MULTILINE. La segunda versión, slurp-in-whole-file, no debe tener esa marca, ya que depende de la coincidencia de una nueva línea. La primera versión crea una línea única especial y elimina cualquier nueva línea en el proceso. – steveha

1

grep -A1 "exportación a" nombre de archivo | grep -B1 "excel"

+2

Esta solución no asegura que "exportar a" esté al lado de "excel". Coincidirá, por ejemplo, con "exportar a \ n blah blah blah blah excel". – stepthom

+0

Tampoco coincide con "export \ npara sobresalir" y no se escala para buscar una cadena que contenga muchos espacios. – Keelan

Cuestiones relacionadas