bash と zsh が [-1] を 1 として評価するのはなぜですか?

bash と zsh が [-1] を 1 として評価するのはなぜですか?

私はこの驚くべき動作に気づきましたが、何が起こっているのかよくわかりません。

$ 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]

手がかりを探しているときに、次の引用を見つけました。

https://github.com/mvdan/sh

注意点

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 文字の名前を持つファイルが存在する場合、グロブが一致し、ファイル名が取得されます。そのようなファイルが存在しない場合、グロブは変更されません。-1

PS: 以下でも動作します-:

$ touch ./-
$ bash -c 'echo [-1]'
-

関連情報