![Почему bash и zsh оценивают [-1] как 1?](https://rvso.com/image/1681636/%D0%9F%D0%BE%D1%87%D0%B5%D0%BC%D1%83%20bash%20%D0%B8%20zsh%20%D0%BE%D1%86%D0%B5%D0%BD%D0%B8%D0%B2%D0%B0%D1%8E%D1%82%20%5B-1%5D%20%D0%BA%D0%B0%D0%BA%201%3F.png)
Я заметил это удивительное поведение и не могу понять, что происходит:
$ bash -c 'echo [-1]'
1
$ zsh -c 'echo [-1]'
1
Похоже, что анализатор команд пытается оценить выражение:
$ echo [1,2,3]
1
$ echo [123-33]
1
Потому что если выражение взято в кавычки или указано, что скобка — это просто скобка, то странная оценка опускается.
$ echo \[123-33]
[123-33]
$ echo [123-33\]
[123-33]
$ echo '[123-33]'
[123-33]
В поисках подсказок я нашел эту цитату:
Предостережения
При индексации ассоциативных массивов Bash всегда используйте кавычки. В противном случае статический парсер должен будет предположить, что индекс является арифметическим выражением.
$ echo '${array[spaced string]}' | shfmt 1:16: not a valid arithmetic operator: string $ echo '${array[dash-string]}' | shfmt ${array[dash - string]}
Не уверен, что с этим делать, потому что нет массива, о котором можно было бы говорить в контекстеecho [1-1]
Конечно, это может быть вызвано чем-то в моей собственной среде, но когда я проверяю, то вижу, что это не так:
$ 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
Но опять же, на Ubuntu-боксе я получаю другой результат:
$ bash --version | sed 1q; echo [1-1]
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
[1-1]
Отключение всех опций не меняет это поведение.
for i in `shopt | awk '/on$/ { print $1}'`; do shopt -u $i;done
Есть ли у вас какие-либо идеи, что заставляет это выражение в скобках вычисляться и почему результат равен 1?
решение1
1
Это происходит только в том случае, если в текущем каталоге есть файл с указанным именем .
$ bash -c 'echo [-1]'
[-1]
$ touch 1
$ bash -c 'echo [-1]'
1
$ rm 1
$ bash -c 'echo [-1]'
[-1]
Почему? Оболочка делает подстановку, [-1]
которая соответствует файлам с именем -
или 1
. Так что если файл с таким односимвольным именем существует, подстановка совпадает, и вы получаете имя файла. Если такого файла не существует, подстановка остается неизменной.
PS: Также работает с -
:
$ touch ./-
$ bash -c 'echo [-1]'
-