it-swarm-es.tech

¿Cómo busco múltiples patrones con un patrón que tenga un carácter de tubería?

Quiero encontrar todas las líneas en varios archivos que coincidan con uno de los dos patrones. Traté de encontrar los patrones que estoy buscando escribiendo

grep (foo|bar) *.txt

pero el Shell interpreta el | como una tubería y se queja cuando bar no es un ejecutable.

¿Cómo puedo buscar múltiples patrones en el mismo conjunto de archivos?

681
Dan

Primero, debe proteger el patrón de la expansión del Shell. La forma más fácil de hacerlo es poner comillas simples alrededor. Las comillas simples evitan la expansión de cualquier cosa entre ellas (incluidas las barras invertidas); lo único que no puedes hacer es tener comillas simples en el patrón.

grep -- 'foo*' *.txt

(también tenga en cuenta el -- marcador de fin de opción para detener algunas implementaciones de grep incluyendo GNU grep) de tratar un archivo llamado -foo-.txt por ejemplo (el Shell lo expandiría desde *.txt) para ser tomado como una opción (aunque sigue un argumento de no opción aquí)).

Si necesita una cotización simple, puede escribirla como '\'' (final de la cadena literal, comilla literal, cadena abierta literal).

grep -- 'foo*'\''bar' *.txt

En segundo lugar, grep admite al menos¹ dos sintaxis para patrones. La antigua sintaxis predeterminada ( expresiones regulares básicas ) no admite la alternancia (|), aunque algunas versiones lo tienen como una extensión, pero escrito con una barra invertida.

grep -- 'foo\|bar' *.txt

La forma portátil es usar la sintaxis más nueva, expresiones regulares extendidas . Necesitas pasar el -E opción a grep para seleccionarlo (anteriormente se hacía con el egrep comando separado²)

grep -E -- 'foo|bar' *.txt

Otra posibilidad cuando solo está buscando cualquiera de varios patrones (en lugar de construir un patrón complejo usando disyunción) es pasar múltiples patrones a grep. Puede hacer esto precediendo cada patrón con el -e opción.

grep -e foo -e bar -- *.txt

O ponga patrones en varias líneas:

grep -- 'foo
bar' *.txt

O almacene esos patrones en un archivo, uno por línea y ejecute

grep -f that-file -- *.txt

Tenga en cuenta que si *.txt se expande a un solo archivo, grep no prefijará las líneas coincidentes con su nombre como lo hace cuando hay más de un archivo. Para evitar eso, con algunas implementaciones de grep como GNU grep, puede usar el -H opción, o con cualquier implementación, puede pasar /dev/null como argumento adicional.


¹ algunas implementaciones de grep admiten incluso más como las compatibles con Perl con -P, o aumentadas con -X, -K para comodines ksh ...

² mientras egrep ha sido desaprobado por POSIX y a veces ya no se encuentra en algunos sistemas, en otros sistemas como Solaris cuando POSIX o GNU utilidades no se han instalado, entonces egrep es su única opción ya que /bin/grep no admite ninguno de -e, -f, -E, \| o patrones de varias líneas

egrep "foo|bar" *.txt

o

grep "foo\|bar" *.txt
grep -E "foo|bar" *.txt

citando selectivamente la página de manual de gnu-grep:

   -E, --extended-regexp
          Interpret PATTERN as an extended regular expression (ERE, see below).  (-E is specified by POSIX.)

Matching Control
   -e PATTERN, --regexp=PATTERN
          Use PATTERN as the pattern.  This can be used to specify multiple search patterns, or to protect  a  pattern
          beginning with a hyphen (-).  (-e is specified by POSIX.)

(...)

   grep understands two different versions of regular expression syntax: “basic” and “extended.”  In  GNU grep,  there
   is  no  difference  in  available  functionality  using  either  syntax.   In  other implementations, basic regular
   expressions are less powerful.  The following description applies to extended regular expressions; differences  for
   basic regular expressions are summarized afterwards.

Al principio no leí más, así que no reconocí las sutiles diferencias:

Basic vs Extended Regular Expressions
   In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead  use  the
   backslashed versions \?, \+, \{, \|, \(, and \).

Siempre usé egrep y parens innecesariamente, porque aprendí de los ejemplos. Ahora aprendí algo nuevo. :)

109
user unknown

Como dijo TC1, -F parece ser una opción utilizable:

$> cat text
some text
foo
another text
bar
end of file

$> patterns="foo
bar" 

$> grep -F "${patterns}" text
foo
bar

En primer lugar, debe usar comillas para caracteres especiales. Segundo, aun así, grep no entenderá la alternancia directamente; necesitaría usar egrep, o (con GNU grep solamente) grep -E.

egrep 'foo|bar' *.txt

(Los paréntesis son innecesarios a menos que la alternancia sea parte de una expresión regular más grande).

17
geekosaur

Si no necesita expresiones regulares, es mucho más rápido usar fgrep o grep -F con múltiples parámetros -e, como este:

fgrep -efoo -ebar *.txt

fgrep (alternativamente grep -F) es mucho más rápido que grep normal porque busca cadenas fijas en lugar de expresiones regulares.

8
Moustafa Elqabbany

Puede probar el siguiente comando para obtener el resultado:

egrep 'rose.*Lotus|lotus.*rose' some_file
6
Abhishek

Tubería (|) es un carácter especial de Shell, por lo que debe escaparse (\|) o citado según el manual ( man bash ):

Las comillas se utilizan para eliminar el significado especial de ciertos caracteres o palabras al Shell. Se puede usar para deshabilitar el tratamiento especial para caracteres especiales, para evitar que las palabras reservadas se reconozcan como tales y para evitar la expansión de parámetros.

El encerrar caracteres entre comillas dobles conserva el valor literal de todos los caracteres dentro de las comillas

Una barra invertida no citada (\) es el carácter de escape.

Ver: ¿Qué caracteres se deben escapar en Bash?

Aquí hay algunos ejemplos (usando herramientas no mencionadas aún):

  • Usando ripgrep :

    • rg "foo|bar" *.txt
    • rg -e foo -e bar *.txt
  • Utilizando git grep :

    • git grep --no-index -e foo --or -e bar

      Nota: También admite expresiones booleanas como --and, --or y --not.

Para la operación AND por línea, vea: ¿Cómo ejecutar grep con múltiples patrones AND?

Para la operación AND por archivo, consulte: ¿Cómo verificar que existen todas las cadenas múltiples o expresiones regulares en un archivo?

4
kenorb

Una forma barata y alegre de buscar múltiples patrones:

$ echo "foo" > ewq ; echo "bar" >> ewq ; grep -H -f ewq *.txt ; rm ewq
3
DHDHDHD

Tuve acceso a los registros donde las fechas fueron formateadas estúpidamente: [30/Jun/2013: 08: 00: 45 +0200]

Pero necesitaba mostrarlo como: 30/Jun/2013 08:00:45

El problema es que al usar "OR" en mi declaración grep, recibí las dos expresiones de coincidencia en dos líneas separadas.

Aquí está la solución:

grep -in myURL_of_interest  *access.log  | \
grep -Eo '(\b[[:digit:]]{2}/[[:upper:]][[:lower:]]{2}/[[:digit:]]{4}|[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\b)'   \
| paste - - -d" " > MyAccess.log
3
tsmets

TL; DR: si desea hacer más cosas después de hacer coincidir uno de los múltiples patrones, enciérrelos como en \(pattern1\|pattern2\)

ejemplo: Quiero encontrar todos los lugares donde una variable que contiene el nombre 'fecha' se define como una Cadena o int. (por ejemplo, "int cronDate =" o "String textFormattedDateStamp ="):

cat myfile | grep '\(int\|String\) [a-zA-Z_]*date[a-zA-Z_]* =' 

Con grep -E, No necesita escapar de los paréntesis o la tubería, es decir, grep -E '(int|String) [a-zA-Z_]*date[a-zA-Z_]* ='

2
jeremysprofile

Esto funciona para mi

[email protected]:/home/sshuser# aws ec2 describe-instances --instance-ids i-2db0459d |grep 'STATE\|TAG'

**STATE**   80      stopped

**STATE**REASON     Client.UserInitiatedShutdown    Client.UserInitiatedShutdown: User initiated shutdown

**TAGS**    Name    Magento-Testing [email protected]:/home/sshuser#
1
Mansur Ali

Hay varias formas de hacer esto.

  1. grep 'foo\|bar' *.txt
  2. egrep 'foo|bar' *.txt
  3. find . -maxdepth 1 -type f -name "*.txt" | xargs grep 'foo\|bar'
  4. find . -maxdepth 1 -type f -name "*.txt" | xargs egrep 'foo|bar'

La 3ra y 4ta opción solo grep en los archivos y evitará directorios que tengan .txt en sus nombres.
Entonces, según su caso de uso, puede usar cualquiera de las opciones mencionadas anteriormente.
¡¡Gracias!!

1
Bhagyesh Dudhediya

para agregar a @ respuesta de geekosaur , si tiene múltiples patrones que también contienen pestañas y espacio, use el siguiente comando

grep -E "foo[[:blank:]]|bar[[:blank:]]"

dónde [[:blank:]] es una clase de caracteres RE que representa un espacio o un carácter de tabulación

1
Fuseteam