这个脚本:
a=2
[[ "$a" -eq 2 ]] && echo yes1
[[ $a -eq 2 ]] && echo yes2
[[ a -eq 2 ]] && echo yes3
[[ "a" -eq 2 ]] && echo yes4
不适用于短跑(以及其他一些没有 [[ )。
最后两次“是测试”失败灰(BusyBox灰)。正如我所料。
但是,非常不符合预期:
当使用算术“-eq”(以及其他算术)时,就会发生这种情况。
打印所有四个是克什,克什93,克什,姆克什,巴什和桀骜。
问的
这是“算术扩展”应用于 ( ) 等标签的自然副作用吗a
?
(没什么可看的,继续走吧?)
当引用时( a
) 是否仍应扩展为变量:"a"
?
这是否记录在我尚未调查过的地方?
或者,是一个简单的(非常古老的)错误吗?
编辑
为了真正让你思考,请检查以下内容:
a=2; b=2
[[ "$a" -eq "$b" ]] && echo yes1
[[ $a -eq "$b" ]] && echo yes2
[[ a -eq "$b" ]] && echo yes3
[[ "a" -eq "$b" ]] && echo yes4
[[ "$a" -eq "$b" && "$a" == "$b" ]] && echo new1
[[ $a -eq "$b" && $a == "$b" ]] && echo new2
[[ a -eq "$b" && a == "$b" ]] && echo new3
[[ "a" -eq "$b" && "a" == "$b" ]] && echo new4
所有的都可以工作,只有 new1 和 new2 可以。 var a 没有在 new3 和 4 中扩展。
这意味着 shell 在计算过程中切换模式(算术 - 字符串)。
这对我来说似乎不太明显。至少,在我看来,并不简单。
请注意,灰烬以不同的方式做到这一点。并且还报告错误。
结论:
我不知道正确答案。但我怀疑(查看如此多的 shell 以完全相同的方式执行此操作)这是一种(对于开发人员而言)众所周知的测试应该起作用的方式。我们应该了解事实并适应。
似乎对于数字,-eq
唯一可能应用的“条件表达式”是:
exp1 -eq exp2
true if exp1 is numerically equal to exp2.
-eq
这使得“算术表达式”的两边
而==
唯一可能应用的“条件表达式”是:
string == pattern
true if string matches pattern. ....
这使得左侧成为字符串(没有扩展?),右侧成为模式(这实际上不适用于我提出的测试,因为所有内容都在右侧引用以避免这种复杂性。因此,右侧默认值(被引用)也为字符串(这里没有算术扩展)。
但也许我比我想象的更困惑:-)
你怎么说?
答案1
从man ksh
:
算术表达式使用与 C 语言相同的语法、优先级和表达式结合性。可以使用所有适用于浮点量的 C 语言运算符...可以在算术表达式中按名称引用变量,而无需使用参数扩展语法。当引用变量时,其值将被计算为算术表达式...
条件表达式与
[[
复合命令一起使用来测试属性文件并进行比较字符串。不对[[
和之间的单词执行字段分割和文件名生成]]
。每个表达式都可以由以下一个或多个一元或二元表达式构造而成...还允许以下过时的算术比较:
exp1
-eq
exp2
- 确实,如果
exp1
等于exp2
。
exp1
-ne
exp2
- 确实,如果
exp1
不等于exp2
。
exp1
-lt
exp2
- 确实,如果
exp1
小于exp2
。
exp1
-gt
exp2
- 确实,如果
exp1
大于exp2
。
exp1
-le
exp2
- 确实,如果
exp1
小于或等于exp2
。
exp1
-ge
exp2
- 确实,如果
exp1
大于或等于exp2
。
那里的文档对算术的引用是一致的表达式感到担忧,并且(看得出来很仔细)避免围绕定义的任何自相矛盾[[
复合命令 ]]
关于字符串比较通过明确地还允许一些过时的算术比较在相同的背景下。
从man bash
:
[[
expression
]]
- 返回状态
0
或1
取决于条件表达式的评估expression
。表达式由下面描述的原色组成... 不会对[[
和之间的单词执行分词和路径名扩展]]
;执行~
波形符扩展、${
参数}
和$
变量扩展、$((
算术扩展))
、$(
命令替换)
、<(
进程替换)
和引号删除。"\'
条件运算符,例如-f
必须不加引号才能被识别为主运算符...A多变的可以通过以下形式的语句分配给:
name
=
[value]
如果
value
未给出,则为该变量分配空字符串。所有值都会经历~
波形符扩展、${
参数}
和$
变量扩展、$(
命令替换)
、$((
算术扩展))
和"\'
引号删除...如果多变的有它的整数属性设置,然后value
被评估为$((
算术表达式))
,即使$((
...
))
没有使用扩展...shell允许算术
expressions
在某些情况下要进行评估...评估是在固定宽度整数中完成的,不检查溢出,但除以 0 会被捕获并标记为错误。运算符及其优先级、结合性和值与 C 语言中的相同。允许 Shell 变量作为操作数;参数扩展在表达式求值之前执行。在一个
expression
,shell 变量也可以通过名称引用,而不使用参数扩展语法。变量的值被评估为算术expression
当它被引用时,或者当一个已经被赋予整数属性的变量declare -i
被赋值时... shell 变量不需要打开它的整数属性来在表达式中使用。有条件的
expressions
被使用的[[
复合命令以及test
和[
内置命令测试文件属性并执行字符串和算术比较...
arg1
OP
arg2
OP
-eq
是,-ne
,-lt
,-le
,-gt
, 或之一-ge
。这些算术二元运算符返回 true,如果arg1
等于、不等于、小于、小于或等于、大于或大于或等于arg2
, 分别。arg1
和arg2
可以是正整数或负整数。
我认为,考虑到所有这些背景,您观察到的行为是有道理的,即使那里的文档中没有明确说明它是一种可能性。该文档确实指出了特殊处理参数和整数属性,并清楚地表示之间的差异复合命令和一个内置命令。
比较[[
的是句法与任务相同的意义name
=
value
是句法或者case
word
in...
是句法。然而,test
和[
并不是这样的,而是带有参数的相当独立的过程。我认为,真正了解差异的最佳方法是查看 shell 错误输出:
set '[[ \\ -eq 0 ]]' '[ \\ -eq 0 ]'
for sh in bash ksh
do for exp
do "$sh" -c "$1||$2"
set "$2" "$1"
done; done
bash: [[: \: syntax error: operand expected (error token is "\")
bash: line 0: [: \: integer expression expected
bash: line 0: [: \: integer expression expected
bash: [[: \: syntax error: operand expected (error token is "\")
ksh: \: arithmetic syntax error
ksh: [: \: arithmetic syntax error
ksh: \: arithmetic syntax error
这两个 shell 处理异常的方式不同,但是这两种 shell 的两种情况下差异的根本原因非常相似。
bash
直接调用[[ \\
案例a语法错误- 例如,以同样的方式从不存在的文件进行重定向 - 尽管它从那一点开始(正如我所相信的,错误的)计算||
or 表达式的另一边。bash
做给出[[
表达式 a命令名称在错误输出中,但请注意,它不会像对命令那样讨论您调用它的行号[
。bash
抱怨[
没有收到预期的信息整数表达式作为一个论点,但[[
不必以这种方式抱怨,因为它并不真正需要论点,而且永远不需要预计当它与扩展本身一起解析时,任何东西都可以。ksh
当语法错误时完全停止并且根本[[
不打扰。[
它为两者写入相同的错误消息,但请注意[
分配了一个命令名称那里[[
就是ksh
。只有[
在成功解析命令行并且已经发生扩展之后才会调用 - 它将执行自己的小getopts
例程并获取自己的arg[0c]
和其余部分,但[[
再次作为底层 shell 语法进行处理。
我认为这些bash
文档比版本稍微不太清晰,ksh
因为它们使用了这些术语arg[12]
而不是expression
关于整数比较,但我认为这样做仅仅是因为[[
、[
、 和test
在那个时刻都集中在一起,而后两者确实需要论点而前者只收到一个expression
。
无论如何,整数比较在句法在上下文中,你基本上可以做任何有效的数学运算expression
:
m=5+5 a[m]=10
[[ m -eq 10 ]] &&
[[ m++ -eq 10 ]] &&
[[ m-- -gt 10 ]] &&
[[ ${a[m]} == 10 ]] &&
echo "math evals"
math evals
答案2
这有很好的记录,例如bash
:
[[ expression ]]
[...] Word splitting and pathname expansion
are not performed on the words between the [[ and ]];
tilde expansion, parameter and variable expansion,
arithmetic expansion, command substitution, process
substitution, and quote removal are performed.
或在zsh
:
CONDITIONAL EXPRESSIONS
A conditional expression is used with the [[ compound
command to test...
[...]
In the forms which do numeric comparison,
the expressions exp undergo arithmetic
expansion as if they were enclosed in $((...)).
答案3
[[
不是 POSIX 功能,而是一个ksh88
功能。
如果您想知道发生了什么,您需要阅读 ksh 文档。
由于您似乎有兴趣了解该[[
功能,因此您需要知道这[[
不是一个内置命令,[
而是 shell 语法的一部分,因此它的工作基础与test
命令完全不同。
因此,eg[[ $var == *test? ]]
不需要将右侧的模式放入引号中。