¿Cómo puedo seleccionar un directorio para las líneas que contienen "Foo", pero solo obtienen coincidencias cuando la siguiente línea también contiene "Bar"?
¿Cómo puedo seleccionar un directorio para las líneas que contienen "Foo", pero solo obtienen coincidencias cuando la siguiente línea también contiene "Bar"?
Respuestas:
@ warl0ck me señaló en la dirección correcta pcregrep, pero dije "contiene", no "es", y pregunté sobre un directorio, no un archivo.
Esto parece funcionar para mí.
pcregrep -rMi 'Foo(.*)\n(.*)Bar' .
Grep en sí no parece ser compatible, use pcregrep:
Foo
Bar
Foo
abc
pcregrep -M "Foo\nBar" file
Tiene:
Foo
Bar
Fooy Barcomprendería toda la línea.
Con un sedguión:
#!/bin/sed -nf
/^Foo/{
h # put the matching line in the hold buffer
n # going to nextline
/^Bar/{ # matching pattern in newline
H # add the line to the hold buffer
x # return the entire paragraph into the pattern space
p # print the pattern space
q # quit the script now
}
}
Para usarlo:
chmod +x script.sed
printf '%s\n' * | ./script.sed
El printfaquí muestran todos los archivos en el directorio actual en una línea cada uno, y pasarlo a sed.
Nota : esto se ordena por orden alfabético.
Más información de útiles pattern spacey hold space AQUÍ .
grymoire.com tiene cosas realmente buenas sobre shellprogramación.
h, n, H, x, p, qsignifica? Muy interesante.
pattern space& hold space: grymoire.com/Unix/Sed.html#uh-56 o en francés commentcamarche.net/faq/9536-sed-introduction-a-sed-part-i
Usando grepsolo, puede construir la siguiente tubería:
grep -A1 'Foo' input_file | grep -B1 'Bar' | grep 'Foo'
El primero grepobtendrá todas las líneas que contienen Foo, así como la línea después del partido. Luego obtenemos líneas que contienen Bar, así como la línea antes de la coincidencia, y finalmente extraemos las líneas de esta salida que contienen Foo.
EDITAR: Como señaló Manatwork , hay algunos casos problemáticos a tener en cuenta. Aunque es un desafío interesante, debido a grepla funcionalidad orientada a la línea, cualquier solución con él es probable que sea un 'hack' y probablemente sea mejor usar algo como lo pcregrepque es más adecuado para la tarea en cuestión.
find . -name '*.txt' | xargs grep -A1 'Foo' | grep -B1 'Bar'
Si bien prefiero usar la solución de Nathan pcregrep, aquí hay una solución que usa solo grep
grep -o -z -P 'Foo(.*)\n(.*)Bar' file
Explicación de opciones:
-oimprimir solo parte coincidente. Necesario ya que la inclusión de -zimprimirá todo el archivo (a menos que haya un \ 0 en alguna parte)-z Trate la entrada como un conjunto de líneas, cada una terminada por un byte cero (el carácter ASCII NUL) en lugar de una nueva línea.-P sintaxis perl regex EDITAR: esta versión imprime líneas completas coincidentes
grep -o -P -z '(.*)Foo(.*)\n(.*)Bar(.*)' file
-z. Algunos "(. *)" Antes y después de toda la expresión harán que muestre todas las líneas coincidentes. Por ahora, las subcadenas antes de "Foo" y después de "Bar" no se muestran.
Con awk:
awk '/bar/ && prev != "" {print FILENAME ": " prev "\n" FILENAME ": " $0}
/foo/ {prev=$0; next}
{prev=""}' file1...
(nota general sobre la limitación de awk: tenga en cuenta que si algunos nombres de archivo pueden contener caracteres "=", deberá pasarlos como en ./filenamelugar de filenameawk)