No hay una buena razón por la cual
[[ $a = a|b ]]
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 la extglob
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:
echo a|b
Se echo a
canaliza a b
. a|b
no es una PALABRA , son tres fichas: una a
PALABRA , una |
ficha y una ficha de b
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:
[[ $a = a||b ]]
Debido a que ahora es un a
token seguido de un ||
token seguido de b
, entonces se analiza de la misma manera que:
[[ $a = a || b ]]
Cuál es la prueba que $a
es a
o que la b
cadena no está vacía.
Ahora en:
[[ $a =~ a|b ]]
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 que a|b
sea una sola PALABRA . Pero, desde bash 3.2, si lo haces:
[[ $a =~ 'a|b' ]]
Eso ya no coincide con la a|b
expresión regular sino con la a\|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
[[ $a =~ (ab)*c ]]
ahora trabaja,
[[ $a =~ [)}] ]]
no lo hace Necesitas:
[[ $a =~ [\)}] ]]
[[ $a =~ [')'}] ]]
Que en versiones anteriores de bash
coincidiría incorrectamente en la barra invertida. Ese fue arreglado, pero
[[ $a =~ [^]')'] ]]
No 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.
[[ $a =~ 'a|b' ]]
Está haciendo juego contra la a|b
expresión regular.
Eso significa =~
que también se puede agregar al comando [
/ test
:
[ "$a" '=~' 'a|b' ]
test "$a" '=~' 'a|b'
(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 con ksh93
(aunque bash
fue el shell que apareció por primera vez [[ =~ ]]
), pero aún puede hacerlo BASH_COMPAT=31
o shopt -s compat31
volver al comportamiento anterior (excepto que si [[ $a =~ a|b ]]
bien devolvería un error en bash
3.1, ya no lo hace en bash -O compat31
con las nuevas versiones de bash
).
Espero que aclare por qué dije que las reglas eran confusas y por qué usar:
[[ $a =~ $var ]]
ayuda incluso con la portabilidad a otros proyectiles.
|
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.