¿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
Foo
y Bar
comprendería toda la línea.
Con un sed
guió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 printf
aquí 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 space
y hold space
AQUÍ .
grymoire.com tiene cosas realmente buenas sobre shell
programación.
h, n, H, x, p, q
significa? 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 grep
solo, puede construir la siguiente tubería:
grep -A1 'Foo' input_file | grep -B1 'Bar' | grep 'Foo'
El primero grep
obtendrá 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 grep
la 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 pcregrep
que 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:
-o
imprimir solo parte coincidente. Necesario ya que la inclusión de -z
imprimirá 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 ./filename
lugar de filename
awk)