![¿Por qué bash y zsh evalúan [-1] como 1?](https://rvso.com/image/1681636/%C2%BFPor%20qu%C3%A9%20bash%20y%20zsh%20eval%C3%BAan%20%5B-1%5D%20como%201%3F.png)
He notado este comportamiento sorprendente y no puedo entender muy bien qué está pasando:
$ bash -c 'echo [-1]'
1
$ zsh -c 'echo [-1]'
1
Parece que el analizador de comandos intenta evaluar una expresión:
$ echo [1,2,3]
1
$ echo [123-33]
1
Porque si la expresión está entre comillas, o indica que un corchete es solo un corchete, entonces se omite la evaluación extraña.
$ echo \[123-33]
[123-33]
$ echo [123-33\]
[123-33]
$ echo '[123-33]'
[123-33]
Mientras buscaba pistas, encontré esta cita:
Advertencias
Al indexar matrices asociativas de Bash, utilice siempre comillas. De lo contrario, el analizador estático tendrá que asumir que el índice es una expresión aritmética.
$ echo '${array[spaced string]}' | shfmt 1:16: not a valid arithmetic operator: string $ echo '${array[dash-string]}' | shfmt ${array[dash - string]}
No estoy seguro de qué hacer con ello, porque no hay ningún conjunto del que hablar en el contexto deecho [1-1]
Por supuesto, esto podría deberse a algo en mi propio entorno, pero cuando lo compruebo, no parece ser:
$ env -i HOME=$(mktemp -d) bash --noprofile --norc
bash-5.1$ echo [1-1]
1
$ env -i HOME=$(mktemp -d) /bin/bash-4.4 --noprofile --norc
bash-4.4-4.4$ echo [1-1]
1
Pero, de nuevo, en una caja de Ubuntu obtengo un resultado diferente:
$ bash --version | sed 1q; echo [1-1]
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
[1-1]
Deshabilitar todas las opciones no cambia este comportamiento.
for i in `shopt | awk '/on$/ { print $1}'`; do shopt -u $i;done
¿Tiene alguna idea de qué está causando que se evalúe esta expresión entre corchetes y por qué el resultado es 1?
Respuesta1
Esto solo sucede si tiene un archivo nombrado 1
en el directorio actual.
$ bash -c 'echo [-1]'
[-1]
$ touch 1
$ bash -c 'echo [-1]'
1
$ rm 1
$ bash -c 'echo [-1]'
[-1]
¿Por qué? El shell detecta [-1]
los archivos coincidentes llamados -
o 1
. Entonces, si existe un archivo con un nombre de un carácter, el globo coincide y obtienes el nombre del archivo. Si no existe dicho archivo, el globo permanece sin cambios.
PD: También funciona con -
:
$ touch ./-
$ bash -c 'echo [-1]'
-