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|bcadena, 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, bashespera 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 extglobopció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 acanaliza a b. a|bno es una PALABRA , son tres fichas: una a PALABRA , una |ficha y una ficha de b PALABRA .
Cuando se usa [[ $a = a|b ]], bashespera una PALABRA que obtiene ( a), pero luego encuentra un |token inesperado que causa el error.
Curiosamente, bashno se queja en:
[[ $a = a||b ]]
Debido a que ahora es un atoken seguido de un ||token seguido de b, entonces se analiza de la misma manera que:
[[ $a = a || b ]]
Cuál es la prueba que $aes ao que la bcadena no está vacía.
Ahora en:
[[ $a =~ a|b ]]
bashno 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|bsea una sola PALABRA . Pero, desde bash 3.2, si lo haces:
[[ $a =~ 'a|b' ]]
Eso ya no coincide con la a|bexpresión regular sino con la a\|bexpresió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 bashtiene 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 bashcoincidirí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 bashno 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|bexpresió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, zshya que =somethinghay un operador de shell especial allí).
bash 3.1 solía comportarse como zsh. Cambió en 3.2, presumiblemente para alinearse con ksh93(aunque bashfue el shell que apareció por primera vez [[ =~ ]]), pero aún puede hacerlo BASH_COMPAT=31o shopt -s compat31volver al comportamiento anterior (excepto que si [[ $a =~ a|b ]]bien devolvería un error en bash3.1, ya no lo hace en bash -O compat31con 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 lasshoptconfiguraciones de opciones donde se ve este comportamiento, si son solo aquellas dondeextglobestá activado, ya sea de forma predeterminada o configuración explícita, bueno, ahí estamos.