bash集-e和i=0;我不同意

bash集-e和i=0;我不同意,bash,shell,set,operator-keyword,increment,Bash,Shell,Set,Operator Keyword,Increment,以下带有调试选项“set-e-v”的脚本仅在变量的前一个值为零时在增量运算符处失败 #!/bin/bash set -e -v i=1; let i++; echo "I am still here" i=0; let i++; echo "I am still here" i=0; ((i++)); echo "I am still here" bash GNU bash,版本4.0.331-release x86_64-apple-darwin10,但也有GNU bash,版本4.2.4

以下带有调试选项“set-e-v”的脚本仅在变量的前一个值为零时在增量运算符处失败

#!/bin/bash
set -e -v
i=1; let i++; echo "I am still here"
i=0; let i++; echo "I am still here"

i=0; ((i++)); echo "I am still here"
bash GNU bash,版本4.0.331-release x86_64-apple-darwin10,但也有GNU bash,版本4.2.41-release x86_64-unknown-linux-GNU

有什么想法吗?

如果let的最后一个参数的值为0,则let返回1,因此为非零状态:

从手册中:

   let arg [arg ...]
每个参数都是要计算的算术表达式。如果最后一个参数的计算结果为0,则let返回1;否则返回0

当i为0时,i++的计算结果为0,因为它是一个后增量,因此返回i的前一个值,因此让我们返回1,并且由于set-e,bash存在

以下是一些解决方案:

let ++i         # pre-increment, if you expect `i` to never be -1
let i++ 1       # add an expression evaluating to non-zero
let i++ || true # call true if let returns non-zero
看看布景上的照片-e:

如果一个简单的命令(参见上面的SHELL语法)以非零状态退出,则立即退出。[……]

因此,如果任何语句返回非零的退出代码,shell将退出

查看let命令上的:

如果最后一个参数的计算结果为0,则let返回1;否则返回0

但是等等!i++的答案是1,而不是0!它本该起作用的

同样,答案是增量操作符上的BASH手册页:

id++id-:可变后增量和后减量

好吧,不太清楚。尝试以下shell脚本:

#!/bin/bash
set -e -v
i=1; let ++i; echo "I am still here"
i=0; let ++i; echo "I am still here"

i=0; ((++i)); echo "I am still here"
嗯。。。这和预期的一样,我所做的就是在每一行中将I++更改为++I

i++是一个后增量运算符。这意味着,它在let语句返回一个值后递增i。因为在递增之前我是零,所以let语句返回一个非零值

但是,++i是一个预增量运算符。这意味着它在返回退出状态之前增加i。由于i增加到1,退出状态变为零


我希望这是有道理的

我的问题的答案是不要使用let或shift,或者。。。但是使用

i=$((i+1))
当试图通过设置“退出非零状态代码”来检查bash脚本时

bash手册声明set-e具有“如果简单命令以非零状态退出,则立即退出”的效果

不幸的是,让我们改变,然后。。。返回计算结果“如果最后一个参数的计算结果为0,则返回1;否则返回0”。因此,我们得到的不是状态码,而是某种类型的返回值。有时这个返回值是零,有时是一,这取决于计算。因此,set-e将根据您的计算结果导致脚本退出!!!除非你不使用它或者求助于它,否则就没有办法了

let i++ || true
正如arnaud576875所指出的,顺便说一句,这增加了额外的CPU负担

使用

仅适用于i不是-1的特定情况,如let i++仅适用于i不是0的情况。因此,有一半的解决方案


尽管我喜欢Unix,但我不会以任何其他方式使用它。

没有意义的是,let、set-e和通情达理的人不应该生活在一起,因为没有人会写“let I++| | true”,除非将其作为电子邮件签名。事实上,I++不是增量运算符,而是一个引发人们注意的后增量运算符。大多数人不知道它,除非他们是C程序员,并且他们已经看到了:foo=bar+i++;或者oldfoo=foo++足够多的时间给他们一个脑瘤。不,这不是事实,而是一个“set-e”用来检查健康状况的状态代码,不管操作是否成功完成,用来传递有关计算结果的信息。开发人员认为这是一个特性,而不是一个bug,一个la:let i++|echo“look no hands”,但最终的结果是我们需要重写代码以进行调试-事实上,我不再相信这一点,因为更多的操作都在遵循这一点。顺便说一下,作为一致性问题,bash fori=0;iRight,这是状态码!状态代码在增量完成之前返回,因为这是一个增量后运算符。由于i为零,状态代码为1。这很有道理,尤其是在一次酗酒之后。我同意这是混乱的,并导致了许多错误。这就是为什么我告诉人们不要使用I++,而是使用I++,因为它没有这些有趣的副作用。或者更好的i=$i+i,它可能同样有效,并且非常清楚您想要什么。我从来没有想到一个看起来无害的增量会与set-e发生这种意外的交互。幸运的是我找到了这个问题。这个答案是正确的。我已经做了一个测试脚本来检查我在互联网上找到的其他增量选项,大约10个。联机脚本位于此处:
let i++ || true
let ++i