6 command-line shell bash ksh zsh
这个脚本:
a=2
[[ "$a" -eq 2 ]] && echo yes1
[[ $a -eq 2 ]] && echo yes2
[[ a -eq 2 ]] && echo yes3
[[ "a" -eq 2 ]] && echo yes4
Run Code Online (Sandbox Code Playgroud)
不适用于破折号(以及其他一些没有 [[ )。
在ash (BusyBox ash) 中的最后两个“是”测试失败。正如我所料。
但是,完全不符合预期:
当使用算术 » -eq « 时(和其他一些)会发生这种情况。
打印ksh、ksh93、lksh、mksh、bash和zsh 中的所有四个 yes 。
这是将“算术扩展”应用于 ( 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
Run Code Online (Sandbox Code Playgroud)
一切正常,只有 new1 和 new2 可以。var a 没有在 new3 & 4 中扩展。
这意味着 shell 在计算过程中会切换模式(算术 -- 字符串)。
这对我来说似乎并不那么明显。至少,并不简单,IMO。
请注意,ash 以不同的方式执行此操作。并且还报错。
我不知道正确答案。但我怀疑(看着这么多 shell 以完全相同的方式进行),这是一种众所周知的方式(对开发人员而言),该测试应该以这种方式工作。应该由我们来了解事实并适应。
似乎对于数字-eq,唯一可能适用的“条件表达式”是:
exp1 -eq exp2
true if exp1 is numerically equal to exp2.
Run Code Online (Sandbox Code Playgroud)
这使得-eq“算术表达式”的两边
而==唯一可能适用的“条件表达式”是:
string == pattern
true if string matches pattern. ....
Run Code Online (Sandbox Code Playgroud)
这使得左侧是一个字符串(没有扩展?)而右侧是一个模式(这真的不适用于我提出的测试,因为所有都在右侧引用以避免这种复杂性。所以,右侧默认(被引用)到一个字符串也(这里没有算术扩展)。
但也许我比我更困惑:-)
你怎么说?
来自man ksh:
算术表达式使用与 C 语言相同的表达式语法、优先级和结合性。可以使用适用于浮点量的所有 C 语言运算符... 可以在算术表达式中按名称引用变量,而无需使用参数扩展语法。当一个变量被引用时,它的值被评估为一个算术表达式......
条件表达式与
[[复合命令一起用于测试文件的属性和比较字符串。场分裂和文件名生成不上的话执行[[和]]。每个表达式都可以从以下一元或二元表达式中的一个或多个构造...还允许以下过时的算术比较:
exp1-eqexp2
- 真,如果
exp1等于exp2。
exp1-neexp2
- 是的,如果
exp1不等于exp2。
exp1-ltexp2
- 是的,如果
exp1小于exp2。
exp1-gtexp2
- 是的,如果
exp1大于exp2。
exp1-leexp2
- 真,如果
exp1小于或等于exp2。
exp1-geexp2
- 真,如果
exp1大于或等于exp2。
那里的文档在对算术表达式的引用方面是一致的,并且(显然是小心地)通过明确允许在同一上下文中进行一些过时的算术比较来避免围绕与字符串比较有关的[[ 复合命令 的定义的任何自相矛盾。]]
来自man bash:
[[expression]]
- 返回状态
0或1取决于 condi 的评估?表达expression。表达式由所述原色的下面描述...未在之间的字进行字分裂和路径扩展[[和]];~执行波浪号扩展、${参数}和$变量扩展、$((算术扩展))、$(命令替换)、<(进程替换)和"\'引号删除。条件运算符,例如-f必须不加引号才能被识别为主要...一个变量可以通过以下形式的语句赋值:
name=[value]如果
value未给出,则为变量分配空字符串。所有值都经过~波浪号扩展、${参数}和$变量扩展、$(命令替换)、$((算术扩展))和"\'引号删除...如果变量设置了整数属性,即使不使用扩展,也会将value其计算为$((算术表达式...))$((...))
expressions在某些情况下,shell 允许对算术进行求值... 求值是在固定宽度的整数中完成的,不检查溢出,尽管除以 0 会被捕获并标记为错误。运算符及其优先级、结合性和值与 C 语言中的相同。允许外壳变量作为操作数;在计算表达式之前执行参数扩展。在
expression, shell 变量中也可以按名称引用而不使用参数扩展语法。变量的值expression在被引用时被计算为算术,或者当一个被赋予整数属性的变量declare -i被赋值时......一个shell变量不需要打开它的整数属性来使用表达。条件
expressions是所使用的[[化合物命令和test和[内置命令到测试文件属性,并执行串并算术比较...
arg1OParg2
OP是以下之一-eq,-ne,-lt,-le,-gt,或-ge。如果分别arg1等于、不等于、小于、小于或等于、大于或大于或等于arg2,则这些算术二元运算符返回 true 。arg1并且arg2可以是正整数或负整数。
我认为,鉴于所有这些背景,您观察到的行为是有道理的,即使在那里的文档中没有明确说明它是一种可能性。文档确实指出了对具有整数属性的参数的特殊处理,并清楚地表示复合命令和内置命令之间的区别。
在[[比较语法在同一意义上的分配是语法或者是语法。和,然而,不是这样,而是相当独立的过程,它们接受参数。我认为,真正了解差异的最佳方法是查看 shell 错误输出:name=valuecasewordin...test[
set '[[ \\ -eq 0 ]]' '[ \\ -eq 0 ]'
for sh in bash ksh
do for exp
do "$sh" -c "$1||$2"
set "$2" "$1"
done; done
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
这两个 shell 处理异常的方式不同,但导致这两种情况下两种 shell 差异的根本原因非常相似。
bash直接将此[[ \\案例称为语法错误- 例如,它可能以相同的方式从不存在的文件重定向 - 尽管它从那时开始(我认为,错误地)继续评估||or 表达式的另一侧. bash 确实在错误输出中为[[表达式提供了一个命令名称,但请注意,它不会像讨论命令那样费心讨论您调用它的行号[。bash's[抱怨没有收到它期望的整数表达式作为参数,但[[不必以这种方式抱怨,因为它并不真正接受参数,而且永远不需要期望 当它与扩展本身一起解析时,任何东西。
ksh当[[语法错误时完全停止并且根本不打扰[。它为两者写入相同的错误消息,但请注意,在那里[分配了一个命令名称,其中[[只是ksh. 该[会做自己的小-后命令行已成功解析和扩张已经发生时才调用getopts程序,并获得自己arg[0c]和休息,但[[作为shell语法再次底层的处理。
我认为bash文档比ksh版本稍微不那么清楚,因为它们使用术语arg[12]而不是expression关于整数比较,但我认为这样做仅仅是因为[[, [, 和test在那个时刻都集中在一起,而后两者确实接受了论点,而以前只收到一个expression.
在任何情况下,如果整数比较在语法上下文中没有歧义,您基本上可以执行任何有效的数学运算 mid- expression:
m=5+5 a[m]=10
[[ m -eq 10 ]] &&
[[ m++ -eq 10 ]] &&
[[ m-- -gt 10 ]] &&
[[ ${a[m]} == 10 ]] &&
echo "math evals"
Run Code Online (Sandbox Code Playgroud)
math evals
Run Code Online (Sandbox Code Playgroud)
这有很好的记录,例如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.
Run Code Online (Sandbox Code Playgroud)
或在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 $((...)).
Run Code Online (Sandbox Code Playgroud)