Mi pregunta proviene de ¿Cómo el almacenamiento de la expresión regular en una variable de shell evita problemas al citar caracteres que son especiales para el shell? .
¿Por qué hay un error?
$ [[ $a = a|b ]] bash: syntax error in conditional expression: unexpected token `|' bash: syntax error near `|b'
Dentro
[[ ... ]]
del segundo operando de=
se espera que haya un patrón globbing.¿
a|b
No es un patrón de globo válido? ¿Puedes señalar qué regla de sintaxis viola?Algunos comentarios a continuación señalan que
|
se interpreta como tubería.Luego, cambiar el
=
patrón glob=~
por el patrón regex hace que|
funcione$ [[ $a =~ a|b ]]
Aprendí de Learning Bash p180 en mi publicación anterior que
|
se reconoce como pipe al comienzo de la interpretación, incluso antes de cualquier otro paso de interpretación (incluido analizar las expresiones condicionales en los ejemplos). Entonces, ¿cómo se|
puede reconocer como operador de expresiones regulares cuando se usa=~
, sin ser reconocido como tubería en un uso no válido, como cuando se usa=
? Eso me hace pensar que el error de sintaxis en la parte 1 no significa que|
se interprete como una tubería.Cada línea que el shell lee desde la entrada estándar o un script se llama una tubería; contiene uno o más comandos separados por cero o más caracteres de canalización (|). Para cada canalización que lee, el shell lo divide en comandos, configura la E / S para la canalización y luego hace lo siguiente para cada comando (Figura 7-1):
Gracias.
|
es especial) está activado de forma predeterminada en el lado derecho de[[ $var = $pattern ]]
. Sería interesante aislar las versiones y lasshopt
configuraciones de opciones donde se ve este comportamiento, si son solo aquellas dondeextglob
está activado, ya sea de forma predeterminada o configuración explícita, bueno, ahí estamos.pattern='a|b'
y luego expanda sin$pattern
cotizar en el RHS.Respuestas:
No hay una buena razón por la cual
Debería informar un error en lugar de probar si $ a es la
a|b
cadena, mientras[[ $a =~ a|b ]]
que no devuelve un error.La única razón es que
|
generalmente es (fuera y dentro[[ ... ]]
) un personaje especial. En esa[[ $a =
posición,bash
espera un tipo de token que sea una PALABRA normal, como los argumentos o los objetivos de las redirecciones en una línea de comando de shell normal (pero como si laextglob
opción se hubiera habilitado desde bash 4.1).(por WORD aquí, me refiero a una palabra en una gramática de shell hipotética como la descrita por la especificación POSIX , que es algo que el shell analizaría como un token en una línea de comando de shell simple, no otra definición de palabras como el inglés uno de una secuencia de letras o una secuencia de caracteres no espaciado.
foo"bar baz"
,$(echo x y)
, son dos de estas WORD s).En una línea de comando de shell normal:
Se
echo a
canaliza ab
.a|b
no es una PALABRA , son tres fichas: unaa
PALABRA , una|
ficha y una ficha deb
PALABRA .Cuando se usa
[[ $a = a|b ]]
,bash
espera una PALABRA que obtiene (a
), pero luego encuentra un|
token inesperado que causa el error.Curiosamente,
bash
no se queja en:Debido a que ahora es un
a
token seguido de un||
token seguido deb
, entonces se analiza de la misma manera que:Cuál es la prueba que
$a
esa
o que lab
cadena no está vacía.Ahora en:
bash
no puede tener la misma regla de análisis. Tener la misma regla de análisis significaría que lo anterior daría un error y que sería necesario citar eso|
para garantizar quea|b
sea una sola PALABRA . Pero, desde bash 3.2, si lo haces:Eso ya no coincide con la
a|b
expresión regular sino con laa\|b
expresión regular. Es decir, las citas de shell tienen el efecto secundario de eliminar el significado especial de los operadores regexp. Es una característica, por lo que el comportamiento es similar al de[[ $a = "?" ]]
uno, pero los patrones comodín (utilizados en[[ $a = pattern ]]
) son PALABRAS de shell (utilizadas en globos, por ejemplo), mientras que las expresiones regulares no lo son.Así que
bash
tiene que tratar a todos los operadores de expresiones regulares extendidas que son por lo demás normalmente caracteres especiales como shell|
,(
,)
diferente al analizar un argumento del=~
operador.Aún así, tenga en cuenta que mientras
ahora trabaja,
no lo hace Necesitas:
Que en versiones anteriores de
bash
coincidiría incorrectamente en la barra invertida. Ese fue arreglado, peroNo no coincidir en la barra invertida como debería, por ejemplo. Debido a que
bash
no se da cuenta de que)
está dentro de los corchetes, se escapa)
para dar como resultado una[^]\)]
expresión regular que coincide con cualquier carácter pero]
,\
y)
.ksh93
tiene errores mucho peores en ese frente.En
zsh
, es una palabra de shell normal que se espera y citar operadores regexp no afecta el significado de los operadores regexp.Está haciendo juego contra la
a|b
expresión regular.Eso significa
=~
que también se puede agregar al comando[
/test
:(también funciona
yash
. Es=~
necesario citarlo,zsh
ya que=something
hay un operador de shell especial allí).bash 3.1 solía comportarse como
zsh
. Cambió en 3.2, presumiblemente para alinearse conksh93
(aunquebash
fue el shell que apareció por primera vez[[ =~ ]]
), pero aún puede hacerloBASH_COMPAT=31
oshopt -s compat31
volver al comportamiento anterior (excepto que si[[ $a =~ a|b ]]
bien devolvería un error enbash
3.1, ya no lo hace enbash -O compat31
con las nuevas versiones debash
).Espero que aclare por qué dije que las reglas eran confusas y por qué usar:
ayuda incluso con la portabilidad a otros proyectiles.
fuente
[[ $a = a|b ]]
.a|b
No es una cáscara PALABRA aquí, es ela
,|
yb
token. Al igualecho a|b
que no salea|b
o no expande una|b
globo, debe citar eso,|
ya que es un carácter de shell especial que no es válido en ese contexto.[[ $a = (a|b) ]]
funcionaría comoecho (a|b)
funcionaría como(a|b)
es un operador comodín zsh.Pegotes estándar ( "expansión de nombre de archivo") son:
*
,?
y[ ... ]
.|
no es un operador glob válido en configuraciones estándar (no extglob).Tratar:
fuente
|
interpreta literalmente? ¿Por qué hay un error de sintaxis?|
¿no es un operador global, por lo que no se|
interpreta literalmente sin ser citado? Entonces, ¿por qué hay un error de sintaxis?|
es un personaje de control; nunca se trata como un carácter literal de la misma manera que una letra o número.[[ $a = a
no es un comando válido cuya salida se pueda canalizar a otro proceso (al menos eso es lo que el shell pensó que estaba tratando de hacer).Si desea una coincidencia de expresiones regulares, la prueba sería:
fuente