*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, grepy 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 grepcomando.
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 greppor 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 -fo 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 grepcomando 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 grepcomando 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, grepsignifica 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 bpartidos un literal b, b*coincide con cero o más bs, por lo tanto ab*clos 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.*clos partidos ac, akc, ahjglhdfjkdlgjdfkshlgc, incluso acccccchjckhcc, etc. Or
Una clase de personaje . Desde [xy]partidos xo y, [xy]*concuerda con cero o más caracteres, donde cada uno es o bien xo y, por lo tanto p[xy]*qlos 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 \wcoincide 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 bars, por lo tanto foo\(bar\)*bazlos partidos foobaz, foobarbaz, foobarbarbaz, foobarbarbarbaz, etc.
Con las opciones -Eo -P, greptrata 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)bazlugar de foo\(bar\)baz.
man grepproporciona 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 grepacepta 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 --colorbandera, grepresaltará 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=autoque se ejecute, lo cual es suficiente para este propósito, cuando se ejecuta grepdesde la línea de comandos, por lo que es probable que ni siquiera necesite pasar --colormanualmente.
1 Por lo tanto, .*en una expresión regular significa lo que *significa en un globo de shell. Sin embargo, la diferencia es que grepimprime 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 characterslea el documento)