bash set -e and i=0;让 i++ 不同意

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7247279/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 20:59:15  来源:igfitidea点击:

bash set -e and i=0;let i++ do not agree

bashshellsetoperator-keywordincrement

提问by bliako

the following script with debug option 'set -e -v' fails at the increment operator only when the variable has a prior value of zero.

仅当变量的先验值为零时,带有调试选项“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, version 4.0.33(1)-release (x86_64-apple-darwin10) but also GNU bash, version 4.2.4(1)-release (x86_64-unknown-linux-gnu))

bash(GNU bash,版本 4.0.33(1)-release (x86_64-apple-darwin10) 以及 GNU bash,版本 4.2.4(1)-release (x86_64-unknown-linux-gnu))

any ideas?

有任何想法吗?

回答by bliako

the answer to my question is not to use let(or shift, or...) but to use

我的问题的答案不是使用let(或shift,或...),而是使用

i=$((i+1))

when trying to check a bash script by setting 'exit on non-zero status code' with

尝试通过设置“退出非零状态代码”来检查 bash 脚本时

set -e

The bash manual states that set -ehas the effect of 'Exit immediately if a simple command exits with a non-zero status.'.

bash 手册指出set -e具有 '如果简单命令以非零状态退出,则立即退出的效果'。

Unfortunately let(and shiftand ...) return the result of the computation ('If the last arg evaluates to 0, let returns 1; 0 is returned otherwise'). So instead of a status code one gets a return value of some sort. And sometimes this return value will be zero and sometimes one depending on the computation. Therefore set -e will cause the script to exit depending on the result of your computation!!! and there is nothing to do about it unless either you don't use it ever or resort to

不幸的是let(和shift和 ...)返回计算结果('如果最后一个 arg 计算结果为 0,则 let 返回 1;否则返回 0')。因此,不是状态代码,而是某种类型的返回值。有时这个返回值将是零,有时是一,具体取决于计算。因此 set -e 将导致脚本根据您的计算结果退出!!!除非你永远不使用它或诉诸于它,否则没有什么可做的

let i++ || true

as pointed by arnaud576875 which btw adds extra CPU burden.

正如 arnaud576875 所指出的那样,顺便说一句,它增加了额外的 CPU 负担。

Using

使用

let ++i

works only for the specific case that i is not -1, as with let i++which works only for when i is not 0. Therefore half-solutions.

仅适用于 i 不是 -1 的特定情况,就像let i++仅适用于 i 不为 0 时一样。因此是半解。

I love Unix though, I wouldn't have it any other way.

虽然我喜欢 Unix,但我不会有任何其他方式。

回答by Arnaud Le Blanc

If the last argument of letevaluates to 0, let returns 1(so, a non-zero status):

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

From the manual:

   let arg [arg ...]

Each arg is an arithmetic expression to be evaluated. If the last arg evaluates to 0, let returns 1; 0 is returned otherwise.

从手册:

   let arg [arg ...]

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

i++evaluates to zero when iis 0(because it's a post-increment, so the previous value of iis returned), so letreturns 1, and due to set -e, bash exists.

i++iis时计算为零0(因为它是一个后增量,所以i返回了之前的值),所以let返回1,并且由于set -e, bash 存在。

Here are some solutions:

以下是一些解决方案:

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

回答by David W.

Looking at the BASH manpageon the set -e:

纵观BASH手册页set -e

Exit immediately if a simple command (see SHELL GRAMMAR above) exits with a non-zero status. [...]

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

So, if any statement returns a non-zero exit code, the shell will exit.

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

Taking a look at the BASH manpage, on the letcommand:

查看BASH 联机帮助页,在let命令上:

If the last arg evaluates to 0, let returns 1; 0 is returned otherwise.

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

But wait! The answer to i++is a one and not a zero! It should have worked!

可是等等!答案i++是一而不是零!它应该有效!

Again, the answer is with the BASH manpage on the increment operator:

同样,答案是关于增量运算符的 BASH 联机帮助页:

id++ id--: variable post-increment and post-decrement

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

Okay, not so clear. Try this shell script:

好吧,不是很清楚。试试这个 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"

Hmmm... that works as expected, and all I did was change i++to ++iin each line.

嗯...如预期那样的作品,而我所做的是改变i++++i在每一行。

The i++is a post-incrementoperator. That means, it increments iafterthe letstatement returns a value. Since iwas zero beforebeing incremented, the letstatement returns a non-zero value.

i++后增量操作。这意味着,它增加i之后let语句返回一个值。由于递增之前i为零,因此该语句返回一个非零值。let

However, the ++iis a pre-increment operator. That means it increments ibefore returning the exit status. Since iis incremented to a 1, the exit status becomes a zero.

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

I hope this makes sense.

我希望这是有道理的。