為什麼 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]

為什麼? shell 會對[-1]名為-或 的檔案進行比對1。因此,如果存在具有此類單字元名稱的文件,則 glob 匹配並且您將獲得文件名稱。如果不存在這樣的文件,則 glob 保持不變。

PS:它也適用於-

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

相關內容