¿Por qué grep no devuelve lo que espero cuando uso comillas simples?

¿Por qué grep no devuelve lo que espero cuando uso comillas simples?

Tengo un archivo con el siguiente contenido:

sh-4.2$ cat file1
example of multiple
pattern
this is an
example of multipole
sorry multiple
pattern matching
using grep
so the example is the
file itself
-example
-multiple
-bye
tata
!

Mientras busca "-example" en el archivo anterior, el comando grep no proporciona el resultado deseado. Sé que si el patrón contiene '-' entonces se debe usar la opción -e:

En el primer ejemplo utilicé-ejemplodirectamente sin comillas:

sh-4.2$ grep -example file1
example of multiple
example of multipole
so the example is the
-example

-ejemplocon comillas simples:

sh-4.2$ grep '-example' file1
example of multiple
example of multipole
so the example is the
-example

-ejemplocon comillas dobles y caracteres de escape

sh-4.2$ grep "\-example" file1
-example
sh-4.2$

Respuesta1

Bueno, sabes que el patrón de búsqueda contiene un '-', y sabes que cuando el patrón de búsqueda contiene un '-' necesitas usar la -ebandera. Como no está utilizando la -ebandera, el shell interpreta su "patrón" como un argumento (y un parámetro). Puedes ver eso con:

$ grep "-foo" file1
grep: oo: No such file or directory

Por extensión, su código grep "-example" file1le dice al Shell que desea ejecutar grepcon el -eargumento y un parámetro "ejemplo".

Este es el mismo problema con el que nos encontramos cuando intentamos algo así rm -my-silly-file-name: no funcionará y necesitamos usar algo así rm ./-my-silly-file-nameen su lugar. Otra solución sería rm -- -my-silly-file-name. Podemos usar ese modismo aquí:

$ grep -- "-example" < file1
-example

El "--" le dice al shell que todo lo que sigue esnoun argumento.

Alternativamente, puedes simplemente escapar del "-" con un "\", como has visto:

grep "\-example" file1

Este artículo detalla algunos detalles sobre las citas.: la parte relevante esLos parámetros y comandos entre comillas que el shell debe interpretar están entre comillas dobles.Cuando utiliza comillas dobles, el contenido es interpretado por el shell.

Respuesta2

Usted "sabe si el patrón [comienza con] '-' entonces se debe usar la opción -e", pero no lo está usando cuando debería. grep -e -example file1le dará el resultado esperado.

Esto es lo que realmente se ejecuta en cada uno de sus ejemplos:

  • grep -example file1=> grep -e xample file1(-e es necesario)
  • grep '-example' file1=> grep -e xample file1(-e es necesario)
  • grep "\-example" file1=> grep \-example file1(-e no es necesario)

Respuesta3

-Se toma como opción un argumento que comienza con .

En los dos primeros casos, el primer argumento pasado grepes -example, que grepse entiende como -e xample( xampleargumento de la -eopción, así que busque xample).

En el tercer caso \-examplese pasa a grep. Como no comienza con -, no se toma como opción. En su lugar, se toma como una expresión regular. Sin embargo, el comportamiento \-no está especificado según POSIX, por lo que no tiene garantía de con qué coincide. Con la mayoría de greplas implementaciones, \-coincidirá con a -, sin embargo, puede imaginar grepimplementaciones donde \-puede haber un operador especial (consulte, por ejemplo, GNU, grepdonde \+hay un operador especial y no coincide con un literal +).

Si no desea -exampleque se le tome como opción, necesita:

  • grep -- -example file. El --marca el final de las opciones. Todo lo que sigue no es una opción (por lo que el primer argumento es el patrón a buscar y el resto la lista de archivos a buscar).
  • grep -e -example file. Aquí, -examplese toma como argumento de la -eopción.

Ese es el tipo de razón por la que deberías acostumbrarte a escribir:

grep -e "$pattern" file

O

grep -- "$pattern" file

Si no puede garantizarlo, $patternno comenzará con -.

Tenga en cuenta que aquí también puede escribirlo:

grep '[-]example' file

aunque verExpresión entre corchetes (sin rangos) que coincide con un carácter inesperado en bashsobre posibles complicaciones con ese enfoque.

información relacionada