Por que
grep e\\.g\\. <<< "this is an e.g. wow"
y
grep e\.g\. <<< "this is an e.g. wow"
¿hacer la misma cosa?
Si agrego una tercera barra, también tiene el mismo resultado. PERO, una vez que agrego una cuarta barra, ya no funciona. Esto tiene que ver con una pregunta de un examen anterior para una clase. Preguntó si el que tiene dos barras invertidas funcionaría para generar la línea con "por ejemplo". Originalmente pensé que no funcionaría, pero traté de asegurarme y lo hizo. ¿Cuál es la explicación?
bash
shell
regular-expression
quoting
Wyatt Grant
fuente
fuente
\\\.
y daría grep,\.
pero no es así. buena preguntaRespuestas:
Primero, tenga en cuenta que la barra oblicua coincide demasiado:
En lo que respecta a Bash , un período de escape es lo mismo que un período. Bash pasa el período a grep . Para grep, un punto coincide con cualquier cosa.
Ahora, considere:
Cuando Bash ve una doble barra, la reduce a una sola barra y la pasa a grep que, en la primera de las tres pruebas anteriores, ve, como queremos, una sola barra antes de un período. Por lo tanto, esto hace lo correcto.
Con una triple barra, Bash reduce las dos primeras a una sola barra. Entonces ve
\.
. Dado que un período de escape no tiene un significado especial para Bash, esto se reduce a un período simple. El resultado es que grep ve, como queremos, una barra antes de un período.Con cuatro barras, Bash reduce cada par a una sola barra. Bash pasa a grep dos barras y un punto. grep ve las dos barras y un punto y reduce las dos barras a una sola barra literal . A menos que la entrada tenga una barra diagonal seguida de cualquier carácter, no hay coincidencias.
Para ilustrar eso último, recuerde que dentro de las comillas simples, todos los caracteres son literales. Por lo tanto, dadas las siguientes tres líneas de entrada, el comando grep solo coincide en la línea con la barra diagonal en la entrada:
Resumen del comportamiento de Bash
Para Bash, las reglas son
Dos barras se reducen a una sola barra.
Una barra diagonal frente a un carácter normal, como un punto, es solo el carácter normal (punto).
Así:
Hay una manera simple de evitar toda esta confusión: en la línea de comando Bash, las expresiones regulares deben colocarse entre comillas simples. Dentro de comillas simples, Bash deja todo solo.
fuente
echo
declaración que ilustra lo que hace bash en estos casos.\.
o.
. Para bash, ambos son iguales: son equivalentes a un período simple. Por lo tanto, en total, lo que bash entrega a grep es lo mismo para ambos: una barra inclinada seguida de un punto.echo
no es una forma muy confiable de probar regexp debido a la implementación de este programa. Por ejemplo, debajo de mi zsh (eco incorporado)echo \. \\. \\\. \\\\. \\\\\.
da. \. \. \. \.
, pero/bin/echo \. \\. \\\. \\\\. \\\\\.
regresa. \. \. \\. \\.
. Algo asíprintf "%s" ...
es probablemente la mejor manera.El resultado es el mismo solo para su cadena, pero en general esas expresiones regulares hacen cosas diferentes. Modifiquemos un poco su ejemplo agregando el segundo patrón
e,g,
(con comas), el terceroe\.g\.
(puntos), el cuartoe\,g\,
(comas) y la-o
opción de grep para imprimir solo las partes coincidentes.En el siguiente caso
.
coincidirá con cualquier char (aviso''
alrededore.g.
, voy a llegar a eso más adelante)A continuación, escapamos
.
con una barra diagonal inversa\
, por lo que solo.
coincidirá el literal :Pero podemos escapar
\
con otro\
, para que el literal\
coincida seguido de.
(es decir, cualquier carácter):Pero si queremos coincidir sólo
\.
no\,
luego otro\
se necesita para escapar significado especial del punto:Ahora, debido a que no usó el
''
argumento grep, debe agregar otras barras diagonales inversas para escapar de las barras diagonales inversas de la interpretación de shell, por lo tanto:fuente
Cuando haces un
grep e\.g\.
, el shell está consumiendo la barra invertida, por lo que estás haciendo ungrep e.g.
, que coincide. Cuando haces ungrep e\\.g\\.
, el shell vuelve a consumir una barra oblicua, y ahora estás haciendo ungrep e\.\g.
, que nuevamente coincide. Ahora, se ve una barra invertida en el shell\\
. Entonces, cuando tiene\\
, el primero es una secuencia de escape, el segundo es una barra diagonal inversa. Cuando haces ungrep e\\\.g\\\.
, todavía termina siendogrep e\.\g.
, porque no hay una secuencia de escape (\
) antes de la primera\
para que sea literal\
. Tenga en cuenta que \ es una barra invertida, por lo quegrep e\\\\.\\\\g
termina siendogrep e\\.g\\.
, lo que obviamente no coincide.Para ver cómo el shell está viendo lo que estás haciendo, usa echo (por ejemplo,
echo grep e\\.g\\. <<< "this is an e.g. wow"
vs.echo grep e\\\\.g\\\\. <<< "this is an e.g. wow"
)fuente
Los dos comandos producen la misma salida solo para su entrada, pero de lo contrario son diferentes. Para comprender lo que está sucediendo, tenemos que saber cómo se interpreta el parámetro primero
bash
y luego porgrep
.Escapando en bash
\
es un carácter especial que cancela el significado especial del siguiente carácter, incluido él\
mismo. Si el siguiente carácter no tiene un significado especial, se pasa sin cambios. Ejemplos con comando y un resultado:echo \a
:a
- el personaje ordinario escapado le da al personajeecho \\
:\
- el carácter especial escapado le da al personajeecho \\\a
:\a
- combinación especial, ordinariaecho \\\\
:\\
- combinación especial, especialecho
imprimirá la cadena resultante después debash
interpretarla. Más información: documentación de fiesta , los piratas informáticos de bash wiki , especificación POSIX ..
no tiene ningún significado especial enbash
. Es un personaje ordinario para el caparazón. A continuación se muestran las secuencias relevantes para sus ejemplos:echo .
:.
echo \.
:.
echo \\.
:\.
echo \\\.
:\.
echo \\\\.
:\\.
Solución más simple para cadenas literales en bash
Para pasar parámetros literalmente
bash
, puede usar el'
escape de comillas simples . Entre comillas simples no tiene que preocuparse por el significado especial de los caracteres porque la comilla simple es el único carácter con un significado especial allí. Puede insertar una comilla simple después de encerrar la primera parte de la cadena. Ejemploecho 'part1'\''part2'
:part1'part2
Regex en grep
\
es un personaje de escape con un significado similar al debash
..
es un caracter especial que representa una sola ocurrencia de cualquier caracter . Ver: POSIX regex , GNU grep regex . Ejemplos de expresiones regex:.
- coincide con cualquier personaje comoa
o.
\.
- coincide solo.
literalmenteSus ejemplos
En la segunda línea de todos los ejemplos a continuación encontrará equivalente entre comillas simples
'
que muestran qué cadena literal se pasa porbash
agrep
. Luego, después degrep
realizar el escape, el único carácter especial posible en los ejemplos es hacer.
coincidir cualquier carácter. En la tercera línea hay una descripción con la que coincide la expresión.grep e.g. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
cualquier carácterg
cualquier carácter - coincidenciase.g.
y posiblemente otras cadenas comoeagb
grep e\.g\. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
cualquier carácterg
cualquier carácter - coincidenciase.g.
y posiblemente otras cadenas comoexgy
grep e\\.g\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
literalmente - solo coincidee.g.
grep e\\\.g\\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
literalmente - solo coincidee.g.
grep e\\\\.g\\\\. <<< "this is an e.g. wow"
grep 'e\\.g\\.' <<< "this is an e.g. wow"
e\
cualquier personajeg\
cualquier personaje - no coincidee.g.
fuente