¿Cómo puedo grep para esto o aquello (2 cosas) en un archivo?

38

Tengo un archivo que tiene "entonces" y "allí".

yo puedo

$ grep "then " x.x
x and then some
x and then some
x and then some
x and then some

y yo puedo

$ grep "there " x.x
If there is no blob none some will be created

¿Cómo puedo buscar ambos en una sola operación? Lo intenté

$ grep (then|there) x.x

-bash: error de sintaxis cerca del token inesperado `('

y

grep "(then|there)" x.x
durrantm.../code
# (Nothing)
Michael Durrant
fuente

Respuestas:

54

Necesita poner la expresión entre comillas. El error que está recibiendo es el resultado de bash interpretando el (como un carácter especial.

Además, debe decirle a grep que use expresiones regulares extendidas.

$ grep -E '(then|there)' x.x

Sin expresiones regulares extendidas, usted tiene que escapar del |, (, y ). Tenga en cuenta que aquí usamos comillas simples. Bash trata especialmente las barras invertidas entre comillas dobles.

$ grep '\(then\|there\)' x.x

La agrupación no es necesaria en este caso.

$ grep 'then\|there' x.x

Sería necesario para algo como esto:

$ grep 'the\(n\|re\)' x.x

fuente
3
Ver también grep $'then\nthere'y grep -e then -e there. Tenga en cuenta que \|no es estándar en los BRE. El resto es. Trata del golpe barras invertidas especialmente dentro de las comillas dobles sólo antes ", $, \ , `y la nueva línea.
Stéphane Chazelas
1
¿Para qué sirve x.x?
alex
7

Solo un apéndice rápido, la mayoría de los sabores tienen un comando llamado egrep que es grep con -E. Personalmente me gusta mucho mejor escribir

egrep "i(Pod|Pad|Phone)" access.log

Que usar grep -E

Trausti Thor
fuente
2

Lo que se documenta en EXPRESIONES REGULARES en la (o al menos, mi) página de manual es en realidad para expresiones regulares extendidas ;

grep comprende tres versiones diferentes de la sintaxis de expresión regular: "básica", "extendida" y "perl". En GNU grep, no hay diferencia en la funcionalidad disponible entre las sintaxis básica y extendida. En otras implementaciones, las expresiones regulares básicas son menos potentes. La siguiente descripción se aplica a las expresiones regulares extendidas; Las diferencias para las expresiones regulares básicas se resumen a continuación.

Pero grep no los usa de forma predeterminada; necesita el -Einterruptor:

grep "(then|there)" x.x

Porque (de la página de manual nuevamente):

Expresiones regulares básicas vs extendidas

En las expresiones regulares básicas, los metacaracteres?, +, {, |, (Y) pierden su significado especial; en su lugar, use las versiones con barra invertida \ ?, +, {, \ |, (, y).

Entonces también puedes usar:

grep "then\|there" x.x

Dado que los paréntesis son superfluos en este caso.

encerrada dorada
fuente
0

La elegante simplicidad de Bash parece perderse en su enorme página de manual.

Además de las excelentes soluciones anteriores, pensé que trataría de darle una hoja de trucos sobre cómo bash analiza e interpreta las declaraciones . Luego, utilizando esta hoja de ruta, analizaré los ejemplos presentados por el interrogador para ayudarlo a comprender mejor por qué no funcionan según lo previsto.


Nota: Las líneas de script de Shell se usan directamente. Las líneas de entrada escritas se expanden primero en la historia.

Cada línea bash se tokeniza primero o, en otras palabras, se corta en lo que se llaman tokens . (La tokenización ocurre antes de todas las demás expansiones, incluidas llaves, tildes, parámetros, comandos, aritmética, procesos, división de palabras y expansión de nombre de archivo).

Un token aquí significa una parte de la línea de entrada separada (delimitada) por uno de estos metacaracteres especiales:

space,  - White space...
tab, 
newline,

‘<’,    - Redirection & piping...
‘|’, 
‘>’
‘&’,    - And/Both < | > | >>  .or.  &<file descriptor>

‘;’,    - Command termination

‘(’,    - Subshell, closed by -     ‘)’

Bash usa muchos otros caracteres especiales, pero solo estos 10 producen los tokens iniciales.

Sin embargo, debido a que estos metacaracteres también a veces deben usarse dentro de un token, debe haber una forma de quitarles su significado especial. Esto se llama escapar. La fuga se realiza citando una cadena de uno o más caracteres (es decir,'xx..' , "xx.."), o prefijando un carácter individual con un back-slash, (es decir \x). (Es un poco más complicado que esto porque las citas también necesitan ser citadas, y porque las comillas dobles no citan todo, pero esta simplificación servirá por ahora).

No confunda la cita de bash con la idea de citar una cadena de texto, como en otros idiomas. Lo que está entre comillas en bash no son cadenas, sino más bien secciones de la línea de entrada que tienen metacaracteres escapados para que no delimiten tokens.

Tenga en cuenta que hay una diferencia importante entre ' , y ", pero eso es para otro día.

Los metacaracteres restantes sin escape se convierten en separadores de tokens.

Por ejemplo,

$ echo "x"'y'\g
xyg

$ echo "<"'|'\>
<|>

$ echo x\; echo y
x; echo y

En el primer ejemplo, hay dos tokens producidos por un delimitador de espacio: echo y xyz.

Del mismo modo en el segundo ejemplo.

En el tercer ejemplo, el punto y coma se escapó, por lo que hay 4 tokens producidos por un delimitador de espacio, echo, x;, echo, y y. El primer token se ejecuta como comando y toma los siguientes tres tokens como entrada. Tenga en cuenta que el segundo echono se ejecuta.


Lo importante a recordar es que las primeras miradas de bash para los personajes que escapan ( ', "y \), y luego busca delimitadores meta-caracteres sin escape, en ese orden.

Si no se escapa, estos 10 caracteres especiales sirven como tokendelimitadores. Algunos de ellos también tienen un significado adicional, pero ante todo, son delimitadores de fichas.


Que grep espera

En el ejemplo anterior grep necesita estos tokens, grep, string,filename .

El primer intento de la pregunta fue:

$ grep (luego | allí) xx

En este caso (, )y |son meta-caracteres sin escape y así sirven para dividir la entrada en estas fichas: grep, (, then, |, there, ), y x.x. grep quiere ver grep, then|thereyx.x .

El segundo intento de la pregunta fue:

grep "(entonces | allí)" xx

Este tokenizes en grep, (then|there), x.x. Puede ver esto si cambia grep por echo:

echo "(entonces | allí)" xx
(luego | allí) xx

Vista elíptica
fuente