Si recojo 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.
No importa si la expresión está entre comillas.
Pensé que el asterisco indicaba algún número de caracteres desconocidos. ¿Por qué sólo funciona si está al principio de la expresión? Si este es el comportamiento previsto, ¿qué uso en lugar de las expresiones This*String
y *String
?
Respuesta1
un asterisco enexpresiones regularessignifica "coincidir con el elemento anterior 0 o más veces".
En su caso particular con grep 'This*String' file.txt
, está tratando de decir "oye, grep, empareja la palabra Thi
, seguida de s
cero minúsculas o más veces, seguida de la palabra String
". Las minúsculas s
no se encuentran en ninguna parte Example
, por lo que grep las ignora ThisExampleString
.
En el caso de grep '*String' file.txt
, estás diciendo "grep, haz coincidir la cadena vacía (literalmente nada) que precede a la palabra String
". Por supuesto, no es así como ThisExampleString
se supone que debe leerse. (Hayotros posibles significados(puedes probar esto con y sin la -E
bandera, pero ninguno de los significados se parece en nada a lo que realmente quieres aquí).
Sabiendo que eso .
significa "cualquier carácter", podríamos hacer esto: grep 'This.*String' file.txt
. Ahora el comando grep lo leerá correctamente: This
seguido de cualquier carácter (considérelo como una selección de caracteres ASCII) repetido cualquier cantidad de veces, seguido de String
.
Respuesta2
El *
metacarácter en BRE 1 , ERE 1 y PCRE 1 coincide con 0 o más apariciones del patrón agrupado previamente (si un patrón agrupado precede al *
metacarácter), 0 o más apariciones de la clase de carácter anterior (si una clase de carácter es precede al *
metacarácter) o 0 o más apariciones del carácter anterior (si ni un patrón agrupado ni una clase de carácter preceden al *
metacarácter);
Esto significa que en el This*String
patrón, al *
no estar precedido el metacarácter ni por un patrón agrupado ni por una clase de carácter, el *
metacarácter coincide con 0 o más apariciones del carácter anterior (en este caso el s
carácter):
% cat infile
ThisExampleString
ThisString
ThissString
% grep 'This*String' infile
ThisString
ThissString
Para hacer coincidir 0 o más apariciones de cualquier carácter, desea hacer coincidir 0 o más apariciones del .
metacarácter, que coincide con cualquier carácter:
% cat infile
ThisExampleString
% grep 'This.*String' infile
ThisExampleString
El *
metacarácter en BRE y ERE siempre es "codicioso", es decir, coincidirá con la coincidencia más larga:
% cat infile
ThisExampleStringIsAString
% grep -o 'This.*String' infile
ThisExampleStringIsAString
Puede que este no sea el comportamiento deseado; en caso de que no sea así, puede activar grep
el motor PCRE de (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 avidez:
% cat infile
ThisExampleStringIsAString
% grep -Po 'This.*?String' infile
ThisExampleString
1: Expresiones regulares básicas, expresiones regulares extendidas y expresiones regulares compatibles con Perl
Respuesta3
Una de las explicaciones encontradas aquí.enlace:
El asterisco "
*
" no significa lo mismo en expresiones regulares que en comodines; es un modificador que se aplica al carácter único anterior o a una expresión como [0-9]. Un asterisco coincide con cero o más de lo que le precede. Por lo tanto,[A-Z]*
coincide con cualquier número de letras mayúsculas, incluida ninguna, mientras[A-Z][A-Z]*
coincide con una o más letras mayúsculas.
Respuesta4
*
tiene un significado especial tanto como conchaglobocarácter ("comodín") y como expresión regularmetacarácter. Debes tener ambos en cuenta, aunque sicitasu expresión regular, entonces puede evitar que el caparazón la trate de manera especial y asegurarse de que la pase sin cambios agrep
. A pesar dealgo así comoSimilar conceptualmente, lo que *
significa para el caparazón es bastante diferente de lo que significa para grep
.
Primeroel shell lo trata *
como un comodín.
Usted dijo:
No importa si la expresión está entre comillas.
Eso depende de qué archivos existan en cualquier 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. Tu siempre deberiascitaexpresiones regulares para grep
--ycomillas simplessuelen ser los mejores--a menos queestás seguro de que estás bien con elnueve tipos de transformaciones potencialmente sorprendentesel caparazón funciona de otra maneraantesejecutando el grep
comando.
Cuando el shell encuentra un *
carácter que no escitado, significa "cero o más de cualquier carácter" yreemplaza la palabra que lo contienecon una lista de nombres de archivos que coinciden con el patrón. (Los nombres de archivo que comienzan con .
están excluidos, a menos que su patrón comience con.
ohas configurado tu shell para incluirlos de todos modos.) Esto se conoce comoglobo--y también por los nombresexpansión de nombre de archivoyexpansión del nombre de ruta.
El efecto con grep
normalmente será que el primer nombre de archivo coincidente se toma como expresión regular, incluso si sería bastante obvio para un lector humano que esnopensado como una expresión regular, mientras que todos los demás nombres de archivos enumerados automáticamente desde su global se toman como archivosadentrodonde buscar coincidencias. (No ve la lista; se pasa de forma opaca a grep
.) Prácticamente no desea que esto suceda.
La razón por la que esto esa vecesno es un problema, y en su caso particular, al menoshasta ahora, no fue... es que *
se quedará solosi todo lo siguiente es cierto:
HabíaNoarchivos cuyos nombres coinciden. ...Oha desactivado el globbing en su shell, generalmente con
set -f
o su equivalenteset -o noglob
. Pero esto es poco común y probablemente sabrás que lo hiciste.Está utilizando un shell cuyo comportamiento predeterminado es dejarlo
*
solo cuando no hay nombres de archivos coincidentes. Este es el caso en Bash, que estásprobablementeusando, pero no en todos los shells estilo Bourne. (El comportamiento predeterminado en el popular shell Zsh, por ejemplo, es que los globos(a)expandir o(b)producir un error.)...Oha cambiado este comportamiento de su shell; la forma en que se hace varía según el shell.Usted no tienede lo contrariole dijo a su caparazón que permitiera reemplazar los globos connadacuando no hay archivos coincidentes, ni fallar con un mensaje de error en esta situación. En Bash eso se habría hecho habilitando el
nullglob
ofailglob
opción de shell, respectivamente.
A veces puedes confiar en los números 2 y 3, pero rara vez puedes confiar en el número 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 desaparecerá.
Entoncesel grep
comando lo trata *
como un cuantificador.
Las otras respuestas, como aquellaspor Sergiy Kolodyazhnyypor kos- También aborde este aspecto de esta pregunta, de maneras algo diferentes. Así que animo a aquellos que aún no los han leído a que lo hagan, ya sea antes o después de leer el resto de esta respuesta.
Suponiendo que *
llegue a grep, lo que las citas deberían garantizar, grep
entonces se entiende que significa queel elemento que lo precedepuede ocurrir cualquier cantidad de 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. Texto que encaja concualquierde esas posibilidades serán igualadas.
¿Qué quiero decir con "artículo"?
un solopersonaje. Dado que
b
coincide con un literalb
,b*
coincide con cero o másb
s, por lo tantoab*c
coincide conac
,,,, etc.abc
abbc
abbbc
Del mismo modo, desde
.
coincide con cualquier personaje,.*
coincide con cero o más caracteres1, por lo tantoa.*c
coincide conac
,akc
,ahjglhdfjkdlgjdfkshlgc
, paracccccchjckhcc
, etc.OAclase de personaje. Dado que coincide
[xy]
conx
oy
, coincide con[xy]*
cero o más caracteres donde cada uno esx
oy
, por lo tantop[xy]*q
coincide conpq
,,,,,,,,,,, etc.pxq
pyq
pxxq
pxyq
pyxq
pyyq
pxxxq
pxxyq
Esto también se aplica aformas taquigráficasde clases de personajes como
\w
,\W
,\s
y\S
. Dado que\w
coincide con cualquier carácter de palabra,\w*
coincide con cero o más caracteres de palabra.OAgrupo. Dado que coincide
\(bar\)
con cero o más s, coincide con , , , etc.bar
\(bar\)*
bar
foo\(bar\)*baz
foobaz
foobarbaz
foobarbarbaz
foobarbarbarbaz
Con las opciones
-E
o-P
,grep
trata su expresión regular como unaANTES DEoPCRErespectivamente, en lugar de comoBRE, y luego los grupos están rodeados por(
)
en lugar de\(
\)
, por lo que usarías(bar)
en lugar de\(bar\)
yfoo(bar)baz
en lugar defoo\(bar\)baz
.
man grep
ofrece una explicación razonablemente accesible de la sintaxis BRE y ERE al final, además de enumerar todas las opciones de línea de comandos grep
aceptadas al principio. Recomiendo esa página del manual como recurso, y tambiénla documentación de GNU Grepyeste 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 recibe información de su terminal. Introduzca líneas; las líneas que se le devuelven son las que contenían texto que coincidía con su patrón. Para salir, presione Ctrl+ Dal comienzo de una línea, lo que indica el final de la entrada. (O puede presionar Ctrl+ Ccomo ocurre con la mayoría de los programas de línea de comandos). Por ejemplo:
grep 'This.*String'
Si usa la --color
bandera, grep
resaltará el específicopartesde sus líneas que coincidieron con su expresión regular, lo cual es muy útil tanto para descubrir qué hace una expresión regular como para encontrar lo que busca una vez que lo hace. De forma predeterminada, los usuarios de Ubuntu tienen un alias de Bash que hace grep --color=auto
que se ejecute (lo cual es suficiente para este propósito) cuando lo ejecuta grep
desde la línea de comandos, por lo que probablemente ni siquiera necesite pasarlo --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 lugaren ellos, por lo que normalmente no es necesario tenerlo .*
al principio o al final de una expresión regular.