我注意到了这种令人惊讶的行为并且不太明白发生了什么:
$ 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]
为什么?shell 会对[-1]
匹配名为-
或 的文件进行通配符1
。因此,如果存在具有此类单字符名称的文件,则通配符将匹配并获取文件名。如果不存在此类文件,则通配符保持不变。
PS:它还适用于-
:
$ touch ./-
$ bash -c 'echo [-1]'
-