utiliza usar txt siguientes sera salir por opciones líneas las ejemplos devuelta cómo cuál con como comando buscar archivos regex linux grep

regex - usar - ¿Cómo encontrar patrones en múltiples líneas usando grep?



opciones de grep unix (21)

Aquí hay una solución inspirada por esta respuesta :

  • si ''abc'' y ''efg'' pueden estar en la misma línea:

    grep -zl ''abc.*efg'' <your list of files>

  • si ''abc'' y ''efg'' deben estar en líneas diferentes:

    grep -Pzl ''(?s)abc.*/n.*efg'' <your list of files>

Params:

  • -z Trate la entrada como un conjunto de líneas, cada una terminada por un byte cero en lugar de una nueva línea. es decir, grep amenaza la entrada como una gran línea.

  • -l imprime el nombre de cada archivo de entrada desde el cual normalmente se imprimiría la salida.

  • (?s) active PCRE_DOTALL, lo que significa que ''.'' encuentra cualquier personaje o nueva línea.

Quiero encontrar archivos que tengan "abc" Y "efg" en ese orden, y esas dos cadenas están en diferentes líneas en ese archivo. Ejemplo: un archivo con contenido:

blah blah.. blah blah.. blah abc blah blah blah.. blah blah.. blah blah.. blah efg blah blah blah blah.. blah blah..

Debería ser emparejado


Como alternativa a la respuesta de Balu Mohan, es posible imponer el orden de los patrones utilizando solo grep , head y tail :

for f in FILEGLOB; do tail $f -n +$(grep -n "pattern1" $f | head -n1 | cut -d : -f 1) 2>/dev/null | grep "pattern2" &>/dev/null && echo $f; done

Aunque esta no es muy bonita. Formateado más legible:

for f in FILEGLOB; do tail $f -n +$(grep -n "pattern1" $f | head -n1 | cut -d : -f 1) 2>/dev/null / | grep -q "pattern2" / && echo $f done

Esto imprimirá los nombres de todos los archivos donde aparece "pattern2" después de "pattern1" , o donde ambos aparecen en la misma línea :

$ echo "abc def" > a.txt $ echo "def abc" > b.txt $ echo "abcdef" > c.txt; echo "defabc" > d.txt $ for f in *.txt; do tail $f -n +$(grep -n "abc" $f | head -n1 | cut -d : -f 1) 2>/dev/null | grep -q "def" && echo $f; done a.txt c.txt d.txt

Explicación

  • tail -n +i - imprime todas las líneas después del i ésimo, inclusive
  • grep -n - anteponer líneas coincidentes con sus números de línea
  • head -n1 - imprime solo la primera fila
  • cut -d : -f 1 - imprime la primera columna de corte usando : como el delimitador
  • 2>/dev/null - salida de error de silencio de tail que ocurre si la expresión $() regresa vacía
  • grep -q - silent grep y devuelve inmediatamente si se encuentra una coincidencia, ya que solo estamos interesados ​​en el código de salida

Con buscador de plata :

ag ''abc.*(/n|.)*efg''

similar a la respuesta del portador del anillo, pero con ag en su lugar. Las ventajas de velocidad del buscador de plata podrían brillar aquí.


Depende mucho de pcregrep, pero con grep más nuevo no es necesario instalar pcregrep para muchas de sus características. Solo usa grep -P .

En el ejemplo de la pregunta del OP, creo que las siguientes opciones funcionan bien, con la segunda mejor coincidencia de cómo entiendo la pregunta:

grep -Pzo "abc(.|/n)*efg" /tmp/tes* grep -Pzl "abc(.|/n)*efg" /tmp/tes*

Copié el texto como / tmp / test1 y borré la ''g'' y guardé como / tmp / test2. Aquí está el resultado que muestra que el primero muestra la cadena coincidente y el segundo muestra solo el nombre del archivo (típico -o es mostrar coincidencia y típico -l es mostrar solo el nombre del archivo). Tenga en cuenta que la ''z'' es necesaria para líneas múltiples y ''(. | / N)'' significa que debe coincidir con ''cualquier cosa que no sea nueva línea'' o ''nueva línea'' - es decir, cualquier cosa:

user@host:~$ grep -Pzo "abc(.|/n)*efg" /tmp/tes* /tmp/test1:abc blah blah blah.. blah blah.. blah blah.. blah efg user@host:~$ grep -Pzl "abc(.|/n)*efg" /tmp/tes* /tmp/test1

Para determinar si su versión es lo suficientemente nueva, ejecute man grep y vea si algo similar a esto aparece cerca de la parte superior:

-P, --perl-regexp Interpret PATTERN as a Perl regular expression (PCRE, see below). This is highly experimental and grep -P may warn of unimplemented features.

Eso es de GNU grep 2.10.


El patrón de archivo *.sh es importante para evitar que los directorios sean inspeccionados. Por supuesto, algunas pruebas podrían evitar eso también.

for f in *.sh do a=$( grep -n -m1 abc $f ) test -n "${a}" && z=$( grep -n efg $f | tail -n 1) || continue (( ((${z/:*/}-${a/:*/})) > 0 )) && echo $f done

los

grep -n -m1 abc $f

busca el máximo de 1 coincidencia y devuelve (-n) el número de lienzo. Si se encontró una coincidencia (test -n ...) encuentra el último partido de efg (encuentra todo y toma el último con tail -n 1).

z=$( grep -n efg $f | tail -n 1)

else continuar

Dado que el resultado es algo así como 18:foofile.sh String alf="abc"; necesitamos cortar de ":" hasta el final de la línea.

((${z/:*/}-${a/:*/}))

Debería devolver un resultado positivo si el último partido de la segunda expresión ha pasado la primera coincidencia de la primera.

Luego reportamos el nombre de archivo echo $f .


Esto debería funcionar también ?!

perl -lpne ''print $ARGV if /abc.*?efg/s'' file_list

$ARGV contiene el nombre del archivo actual al leer las búsquedas del modificador de la file_list /s de file_list /s en la línea nueva.


Esto debería funcionar:

cat FILE | egrep ''abc|efg''

Si hay más de una coincidencia, puede filtrar usando grep -v


Esto se puede hacer fácilmente al usar tr para reemplazar las líneas nuevas con algún otro caracter:

tr ''/n'' ''/a'' | grep ''abc.*def'' | tr ''/a'' ''/n''

Aquí, estoy usando el carácter de alarma, /a (ASCII 7) en lugar de una nueva línea. Esto casi nunca se encuentra en su texto, y grep puede hacer coincidirlo con a . , o unirlo específicamente con /a .


Grep no es suficiente para esta operación.

pcregrep que se encuentra en la mayoría de los sistemas Linux modernos se puede usar como

pcregrep -M ''abc.*(/n|.)*efg'' test.txt

Hay un pcre2grep más pcre2grep también. Ambos son proporcionados por el proyecto PCRE .

pcre2grep está disponible para Mac OS X a través de puertos Mac como parte del puerto pcre2 :

% sudo port install pcre2

y a través de Homebrew como:

% brew install pcre


Lancé una alternativa de grep hace unos días que sí es compatible con esto, ya sea a través de la coincidencia de líneas múltiples o el uso de condiciones, con suerte es útil para algunas personas que buscan aquí. Así es como se verían los comandos del ejemplo:

Multilínea: sift -lm ''abc.*efg'' testfile
Condiciones: sift -l ''abc'' testfile --followed-by ''efg''

También puede especificar que ''efg'' tenga que seguir ''abc'' dentro de una cierta cantidad de líneas:
sift -l ''abc'' testfile --followed-within 5:''efg''

Puede encontrar más información sobre sift-tool.org .


Mientras que la opción sed es la más simple y fácil, el one-liner de LJ lamentablemente no es el más portátil. Quienes se queden con una versión del C Shell necesitarán escapar de sus explosiones:

sed -e ''/abc/,/efg//!d'' [file]

Desafortunadamente, esto no funciona en bash et al.


No estoy seguro si es posible con grep, pero sed lo hace muy fácil:

sed -e ''/abc/,/efg/!d'' [file-with-content]


No sé cómo haría eso con grep, pero haría algo como esto con awk:

awk ''/abc/{ln1=NR} /efg/{ln2=NR} END{if(ln1 && ln2 && ln1 < ln2){print "found"}else{print "not found"}}'' foo

Sin embargo, debe tener cuidado de cómo hacer esto. ¿Desea que la expresión regular coincida con la subcadena o la palabra completa? agregue etiquetas / w según corresponda. Además, aunque esto se ajusta estrictamente a la forma en que indica el ejemplo, no funciona cuando abc aparece una segunda vez después de efg. Si desea manejar eso, agregue un si, según corresponda, en / abc / case, etc.


Puedes hacerlo fácilmente si puedes usar Perl.

perl -ne ''if (/abc/) { $abc = 1; next }; print "Found in $ARGV/n" if ($abc && /efg/); }'' yourfilename.txt

También puede hacer eso con una sola expresión regular, pero eso implica tomar todo el contenido del archivo en una sola cadena, lo que podría terminar ocupando demasiada memoria con archivos grandes. Para completar, aquí está ese método:

perl -e ''@lines = <>; $content = join("", @lines); print "Found in $ARGV/n" if ($content =~ /abc.*efg/s);'' yourfilename.txt


Si está dispuesto a usar contextos, esto podría lograrse escribiendo

grep -A 500 abc test.txt | grep -B 500 efg

Esto mostrará todo entre "abc" y "efg", siempre que estén dentro de las 500 líneas entre sí.


Si necesita que ambas palabras se cierren entre sí, por ejemplo, no más de 3 líneas, puede hacer esto:

find . -exec grep -Hn -C 3 "abc" {} /; | grep -C 3 "efg"

El mismo ejemplo, pero solo filtra archivos * .txt:

find . -name *.txt -exec grep -Hn -C 3 "abc" {} /; | grep -C 3 "efg"

Y también puede reemplazar el comando grep con el comando egrep si también lo desea con expresiones regulares.


Tristemente, no puedes. De los documentos grep :

grep busca en los ARCHIVOS de entrada nombrados (o en la entrada estándar si no se nombran los archivos, o si se da un solo guión-menos (-) como nombre de archivo) para las líneas que contienen una coincidencia con el PATRÓN dado.


awk one-liner:

awk ''/abc/,/efg/'' [file-with-content]


puede usar grep en caso de que no esté interesado en la secuencia del patrón.

grep -l "pattern1" filepattern*.* | xargs grep "pattern2"

ejemplo

grep -l "vector" *.cpp | xargs grep "map"

grep -l encontrará todos los archivos que coinciden con el primer patrón, y xargs grep para el segundo patrón. Espero que esto ayude.


sed debería ser suficiente ya que el cartel LJ declaró anteriormente,

en lugar de! d puedes simplemente usar p para imprimir:

sed -n ''/abc/,/efg/p'' file


#!/bin/bash shopt -s nullglob for file in * do r=$(awk ''/abc/{f=1}/efg/{g=1;exit}END{print g&&f ?1:0}'' file) if [ "$r" -eq 1 ];then echo "Found pattern in $file" else echo "not found" fi done