英文:
Explain BASH code line let RETVAL=$((RETVAL|$?))
问题
我正在寻找对BASH中来自shell脚本的以下行的解释。我通常熟悉所有单个的内置命令和$(( ))的使用。我对这一行中按位OR运算符比较的是什么有点困惑。
let RETVAL=$((RETVAL|$?))
英文:
I'm looking for some explanation of the below line of BASH from a shell script. I'm generally familiar with all the individual builtins and the use of $(( )). I'm a bit confused about what the bitwise OR operator is comparing in this line.
let RETVAL=$((RETVAL|$?))
答案1
得分: 2
在双重括号内部,表达式的计算不作为命令处理,而是作为算术表达式处理。
因此,这不是一个管道操作符,而是一个按位或操作符。
在这种情况下,它会设置变量RETVAL
中与上一个语句的结果中已设置的位相同的位(包含在特殊变量$?
中)。
这可能只是滥用按位或作为逻辑运算符,因为结果仅在RETVAL
的先前值和$?
都为零时才为零(通常解释为成功/真)。换句话说,在多个命令之后反复使用这个操作只有在它们都返回零时才会得到零的结果。
英文:
Inside double parentheses, the expression is evaluated not as a command, but as an arithmetic expression.
Consequently, this is not a pipe operator but a bitwise or operator.
In this case, it will set any bits in the variable RETVAL
which are set in the result of the last statement (as contained in the special variable $?
).
It's possible that this is just abusing bitwise or as a logical operator, since the result will be zero (generally interpreted as success / true) only if both the previous value of RETVAL
and $?
are zero. In other words, repeatedly using this after multiple commands gives you a zero result only if they all returned zero.
答案2
得分: 1
这通常意味着有人正在对多个不同操作的退出状态进行OR运算,以得到组合的退出状态。
let
是一种过时的进入算术上下文的方法;(( ))
和 $(( ))
是现代的替代方法;因此,下面的代码将更倾向于使用更现代的仅适用于Bash的语法($(( ))
既现代又可移植,但需要您确保它评估的值没有意外的副作用,而(( ))
现代但不可移植,let
既不可移植也不现代)。
假设您希望始终运行函数 foo1
,foo2
和 foo3
,并报告它们是否有任何一个失败:
main() {
local retval=0 # local is the only non-POSIX thing in this example
foo1 || : $(( retval |= $? ))
foo2 || : $(( retval |= $? ))
foo3 || : $(( retval |= $? ))
return "$retval"
}
...将返回一个确定 foo1
、foo2
或 foo3
中的任何一个是否失败的退出状态;如果它们的退出状态作为位掩码运作,将设置高位以指示哪些故障模式发生了。
使用 ||
而不是 ;
是为了明确表示左侧命令的退出状态是“被检查的”,因此 set -e
或 ERR
陷阱不会触发,如果它们不为零。
使用小写变量名是为了遵守https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html 中规定的惯例,其中所有大写字母的名称用于与POSIX指定工具相关的有意义的变量,而至少有一个小写字符的名称是保留供应用程序使用的,并保证不会对POSIX指定工具产生意外的副作用。 (因为设置常规的shell变量会覆盖任何同名的环境变量,相同的约定适用于两种类型的变量)。
英文:
This generally means someone is ORing together the exit status of several different operations to come up with a combined exit status.
let
is an antiquated way of entering an arithmetic context; (( ))
and $(( ))
are the modern alternatives; the code below is thus going to prefer the more modern bash-only syntax ($(( ))
is both modern and portable but makes you responsible for ensuring that the value it evaluates to has no unintended side effects, whereas (( ))
is modern but not portable, and let
is neither portable nor modern).
Let's say that you want to always run functions foo1
, foo2
, and foo3
, and report whether any of them failed:
main() {
local retval=0 # local is the only non-POSIX thing in this example
foo1 || : $(( retval |= $? ))
foo2 || : $(( retval |= $? ))
foo3 || : $(( retval |= $? ))
return "$retval"
}
...will return an exit status that determines whether any of foo1, foo2, or foo3 failed; and if their exit status works as a bitmask, will set high bits to indicate which failure modes took place.
Using ||
instead of ;
is done to make it explicit that the exit status of the commands on the left-hand side are "checked", so set -e
or ERR
traps will not trigger should they be nonzero.
Using lowercase variable names is done for compliance with the conventions specified in https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, whereby all-caps names are used for variables meaningful to POSIX-specified tools, whereas names with at least one lower-case character are reserved for application use and guaranteed not to have unintended side effects on POSIX-specified tools. (Because setting a regular shell variable overwrites any like-named environment variable, the same conventions apply to both types).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论