*
tiene un significado especial tanto como un personaje de shell globbing ("comodín") como un metacarácter de expresión regular . Debe tener en cuenta ambos, aunque si cita su expresión regular, puede evitar que el shell la trate especialmente y asegurarse de que la pase sin cambios grep
. Aunque es algo similar conceptualmente, lo que *
significa para el shell es bastante diferente de lo que significa grep
.
Primero, el shell se trata *
como un comodín.
Tu dijiste:
Si la expresión está entre comillas no hace diferencia.
Eso depende de los archivos que existan en el directorio en el que se encuentre cuando ejecute el comando. Para los patrones que contienen el separador de directorio /
, puede depender de qué archivos existen en todo el sistema. Siempre debe citar expresiones regulares para, grep
y las comillas simples generalmente son las mejores, a menos que esté seguro de que está de acuerdo con los nueve tipos de transformaciones potencialmente sorprendentes que el shell realiza antes de ejecutar el grep
comando.
Cuando el shell encuentra un *
carácter que no está entre comillas , lo hace significar "cero o más de cualquier carácter" y reemplaza la palabra que lo contiene con una lista de nombres de archivo que coinciden con el patrón. (Los nombres de archivo que comienzan con .
están excluidos, a menos que su propio patrón comience .
o haya configurado su shell para incluirlos de todos modos). Esto se conoce como globbing, y también por los nombres de expansión de nombre de archivo y expansión de nombre de ruta .
El efecto con grep
por lo general será que el primer nombre de archivo coincidente se toma como la expresión regular - incluso si sería bastante obvio para un lector humano que está no pretende ser una expresión regular - mientras que todos los otros nombres de archivo enumerados automáticamente de su glob se toman como los archivos dentro de los cuales buscar coincidencias. (No ve la lista, se pasa opacamente a grep
). Prácticamente nunca quiere que esto suceda.
La razón por la que esto a veces no es un problema, y en su caso particular, al menos hasta ahora , no lo fue, es que *
se dejará solo si se cumple todo lo siguiente :
No había archivos cuyos nombres coincidieran. ... O ha deshabilitado el globbing en su caparazón, generalmente con set -f
o el equivalente set -o noglob
. Pero esto es poco común y probablemente sabrás que lo hiciste.
Está utilizando un shell cuyo comportamiento predeterminado es dejar *
solo cuando no hay nombres de archivo coincidentes. Este es el caso de Bash, que probablemente esté utilizando, pero no en todos los shells de estilo Bourne. (El comportamiento predeterminado en el popular shell Zsh, por ejemplo, es que los globos (a) se expandan o (b) produzcan un error.) ... O ha cambiado este comportamiento de su shell: la forma en que se hace varía a través de conchas.
De lo contrario, no le ha dicho a su shell que permita que los globos sean reemplazados por nada cuando no hay archivos coincidentes, ni que falle con un mensaje de error en esta situación. En Bash, eso se habría hecho habilitando la opciónnullglob
o failglob
shell , respectivamente.
A veces puede confiar en el n. ° 2 y n. ° 3, pero rara vez puede confiar en el n. ° 1. Un grep
comando con un patrón sin comillas que funciona ahora puede dejar de funcionar cuando tiene archivos diferentes o cuando lo ejecuta desde un lugar diferente. Cita tu expresión regular y el problema desaparece.
Entonces el grep
comando trata *
como un cuantificador.
Las otras respuestas, como las de Sergiy Kolodyazhnyy y kos, también abordan este aspecto de esta pregunta, de maneras algo diferentes. Así que animo a aquellos que aún no los han leído, que lo hagan antes o después de leer el resto de esta respuesta.
Suponiendo que *
sí llega a grep, lo que debería garantizar la cita, grep
significa que el elemento que lo precede puede ocurrir varias veces , en lugar de tener que ocurrir exactamente una vez . Todavía podría ocurrir una vez. O puede que no esté presente en absoluto. O podría repetirse. Se combinará el texto que se ajuste a cualquiera de esas posibilidades.
¿Qué quiero decir con "artículo"?
Un solo personaje . Desde b
partidos un literal b
, b*
coincide con cero o más b
s, por lo tanto ab*c
los partidos ac
, abc
, abbc
, abbbc
, etc.
Del mismo modo, ya que .
coincide con cualquier carácter , .*
coincide con cero o más caracteres 1 , por lo tanto, a.*c
los partidos ac
, akc
, ahjglhdfjkdlgjdfkshlgc
, incluso acccccchjckhcc
, etc. Or
Una clase de personaje . Desde [xy]
partidos x
o y
, [xy]*
concuerda con cero o más caracteres, donde cada uno es o bien x
o y
, por lo tanto p[xy]*q
los partidos pq
, pxq
, pyq
, pxxq
, pxyq
, pyxq
, pyyq
, pxxxq
, pxxyq
, etc.
Esto también se aplica a taquigrafía formas de clases de personajes como \w
, \W
, \s
, y \S
. Como \w
coincide con cualquier carácter de palabra, \w*
coincide con cero o más caracteres de palabra. O
Un grupo . Desde \(bar\)
partidos bar
, \(bar\)*
partidos cero o más bar
s, por lo tanto foo\(bar\)*baz
los partidos foobaz
, foobarbaz
, foobarbarbaz
, foobarbarbarbaz
, etc.
Con las opciones -E
o -P
, grep
trata su expresión regular como un ERE o PCRE respectivamente, en lugar de como un BRE , y luego los grupos están rodeados por en (
)
lugar de \(
\)
, por lo que usaría en (bar)
lugar de \(bar\)
y en foo(bar)baz
lugar de foo\(bar\)baz
.
man grep
proporciona una explicación razonablemente accesible de la sintaxis BRE y ERE al final, así como una lista de todas las opciones de línea de comandos grep
acepta al principio. Recomiendo esa página del manual como recurso, y también la documentación de GNU Grep y este tutorial / sitio de referencia (que he vinculado a varias páginas, arriba).
Para probar y aprender grep
, recomiendo llamarlo con un patrón pero sin nombre de archivo. Luego toma entrada de su terminal. Introduce líneas; las líneas que se repiten son las que contenían el texto que coincidió con su patrón. Para salir, presione Ctrl+ Dal comienzo de una línea, que señala el final de la entrada. (O puede presionar Ctrl+ Ccomo con la mayoría de los programas de línea de comandos). Por ejemplo:
grep 'This.*String'
Si usa la --color
bandera, grep
resaltará las partes específicas de sus líneas que coinciden con su expresión regular, lo cual es muy útil tanto para descubrir qué hace una expresión regular como para encontrar lo que está buscando una vez que lo hace. Por defecto, los usuarios de Ubuntu tienen un alias Bash que hace grep --color=auto
que se ejecute, lo cual es suficiente para este propósito, cuando se ejecuta grep
desde la línea de comandos, por lo que es probable que ni siquiera necesite pasar --color
manualmente.
1 Por lo tanto, .*
en una expresión regular significa lo que *
significa en un globo de shell. Sin embargo, la diferencia es que grep
imprime automáticamente líneas que contienen su coincidencia en cualquier parte de ellas, por lo que generalmente no es necesario tenerlas .*
al principio o al final de una expresión regular.
* != any number of unknown characters
lea el documento)