Si grep un documento que contiene lo siguiente:
ThisExampleString
... para la expresión This*String
o *String
, no se devuelve nada. Sin embargo, This*
devuelve la línea anterior como se esperaba.
Si la expresión está entre comillas no hace diferencia.
¿Pensé que el asterisco indicaba cualquier número de caracteres desconocidos? ¿Por qué solo funciona si está al comienzo de la expresión? Si este es el comportamiento previsto, ¿qué uso en lugar de las expresiones This*String
y *String
?
command-line
bash
grep
regex
Trae
fuente
fuente
* != any number of unknown characters
lea el documento)Respuestas:
Un asterisco en expresiones regulares significa "hacer coincidir el elemento anterior 0 o más veces".
En su caso particular con
grep 'This*String' file.txt
, está tratando de decir, "hey, grep, concédeme la palabraThi
, seguida des
cero en minúscula o más veces, seguida de la palabraString
". La minúsculas
no se encuentra en ninguna parteExample
, por lo tanto, grep ignoraThisExampleString
.En el caso de
grep '*String' file.txt
, estás diciendo "grep, empareja la cadena vacía, literalmente nada, que precede a la palabraString
". Por supuesto, noThisExampleString
es así como se supone que debe leerse. (Hay otros significados posibles, puede intentar esto con y sin la-E
bandera, pero ninguno de los significados es lo que realmente quiere aquí).Sabiendo que
.
significa "cualquier carácter individual", podríamos hacer esto:grep 'This.*String' file.txt
. Ahora el comando grep lo leerá correctamente:This
seguido de cualquier carácter (piénselo como una selección de caracteres ASCII) repetido cualquier número de veces, seguido deString
.fuente
*
hay un personaje especial y debe citarse o escaparse, por ejemplo, de esta manera:grep 'This*String' file.txt
o esto:grep This\*String file.txt
para no sorprenderse con resultados inesperados.*
es un comodín. En grep,*
es un operador de expresión regular. Ver unix.stackexchange.com/q/57957/70524strace grep .* file.txt |& head -n 1
ystrace grep '.*' file.txt |& head -n 1
. También en realidadgrep
funciona también con cualquier carácter Unicode (por ejemploecho -ne ⇏ | grep ⇏
salidas⇏
)bash
. Esto significa que primerobash
interpreta sus caracteres especiales y solo después de todas las expansiones realizadas, pasa los parámetros al proceso generado. ----- Por ejemplo este comando en Bash:grep This.\*String file.txt
se generan/bin/grep
con estos parámetros: 0grep
, 1:This.*String
2:file.txt
. Tenga en cuenta que Bash eliminó la barra diagonal inversa y el original escapado*
se pasó literalmente.grep This.*String file.txt
normalmente funcionarán porque lo más probable es que no haya un archivo que coincida con la expresión comodín del shellThis.*String
. En tal caso, Bash pasará el argumento literalmente incluido*
.El
*
metacarácter en BRE 1 s, ERE 1 sy PCRE 1 s coincide con 0 o más ocurrencias del patrón agrupado previamente (si un patrón agrupado precede al*
metacarácter), 0 o más ocurrencias de la clase de caracteres anterior (si una clase de caracteres es anterior al*
metacarácter) o 0 o más ocurrencias del carácter anterior (si ni un patrón agrupado ni una clase de caracteres precede al*
metacarácter);Esto significa que en el
This*String
patrón, siendo el*
metacarácter no precedido por un patrón agrupado o una clase de caracteres, el*
metacarácter coincide con 0 o más ocurrencias del carácter anterior (en este caso, els
carácter):Para hacer coincidir 0 o más ocurrencias de cualquier carácter, desea hacer coincidir 0 o más ocurrencias del
.
metacarácter, que coincide con cualquier carácter:El
*
metacarácter en BRE y ERE siempre es "codicioso", es decir, coincidirá con la coincidencia más larga:Este puede no ser el comportamiento deseado; en caso de que no sea así, puede encender el
grep
motor PCRE (usando la-P
opción) y agregar el?
metacarácter, que cuando se coloca después de los metacaracteres*
y+
tiene el efecto de cambiar su codicia:1: Expresiones regulares básicas, Expresiones regulares extendidas y Expresiones regulares compatibles con Perl
fuente
Una de las explicaciones encontradas aquí enlace :
fuente
*
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 cambiosgrep
. Aunque es algo similar conceptualmente, lo que*
significa para el shell es bastante diferente de lo que significagrep
.Primero, el shell se trata
*
como un comodín.Tu dijiste:
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 elgrep
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 agrep
). 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 equivalenteset -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ón
nullglob
ofailglob
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 literalb
,b*
coincide con cero o másb
s, por lo tantoab*c
los partidosac
,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 partidosac
,akc
,ahjglhdfjkdlgjdfkshlgc
, inclusoacccccchjckhcc
, etc. OrUna clase de personaje . Desde
[xy]
partidosx
oy
,[xy]*
concuerda con cero o más caracteres, donde cada uno es o bienx
oy
, por lo tantop[xy]*q
los partidospq
,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. OUn grupo . Desde
\(bar\)
partidosbar
,\(bar\)*
partidos cero o másbar
s, por lo tantofoo\(bar\)*baz
los partidosfoobaz
,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 enfoo(bar)baz
lugar defoo\(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 comandosgrep
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: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 hacegrep --color=auto
que se ejecute, lo cual es suficiente para este propósito, cuando se ejecutagrep
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 quegrep
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.fuente