bash 如何在 if 语句中使用按位运算符?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14318451/
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
How to use bitwise operators in if statements?
提问by EpsilonVector
I want to write something like this:
我想写这样的东西:
if [[ ( releases["token"] & $MASK ) -eq 1 ]]; then
but I get the error that:
但我得到的错误是:
unexpected token `&', conditional binary operator expected
意外标记“&”,预期条件二元运算符
How do I use bitwise operators in if statements?
如何在 if 语句中使用按位运算符?
回答by kev
You can use Arithmetic Expansion
:
您可以使用Arithmetic Expansion
:
(((5&3)==1)) && echo YES || echo NO
It will print YES
它会打印YES
回答by Martin Rüegg
Logic vs Syntax
逻辑与语法
.... or: "What's more to say?"
.... 或:“还有什么好说的?”
At first sight, as pointed out in @chepner's comment, the question might only be one of syntax, which causes the compilation error (unexpected token '&', conditional binary operator expected
). And in fact, @kev's answeraddresses that by using arithmetic expansion, which is applied to the If
statement in @Gustavo's answer.
乍一看,正如@chepner 的评论中指出的那样,问题可能只是语法之一,这会导致编译错误 ( unexpected token '&', conditional binary operator expected
)。事实上,@kev 的回答通过使用算术扩展解决了这个问题,这适用If
于@Gustavo 的回答中的语句 。
However, the question "how to use bitwise operatorsin if statements"is formulated in a more general manner and begs for an answer on how to usebitwise operators to check against $MASK
(It was not the question of "how to avoid a syntax error when using binary comparison").
但是,问题“如何在 if 语句中使用按位运算符”以更一般的方式表述,并要求就如何使用按位运算符进行检查提供答案$MASK
(这不是“如何避免语法错误的问题”使用二进制比较”)。
In fact, it may be assumed that the example code
事实上,可以假设示例代码
if [[ ( releases["token"] & $MASK ) -eq 1 ]]; then
if [[ ( releases["token"] & $MASK ) -eq 1 ]]; then
was a work in progress of finding a solution and is explicitly marked as "something like ...". Now @kev's arbitrary assumption of
是一项正在寻找解决方案的工作,并被明确标记为“类似……”。现在@kev 的任意假设
releases["token"]=3
MASK=5
might hide the fact, that there is also a logical misunderstanding in using -eq 1
in the first place. So while @kev's answer works with the chosen values, the result of the input of e.g. 4
line in
可能会隐藏一个事实,即-eq 1
首先使用时也存在逻辑上的误解。因此,虽然@kev 的答案适用于选定的值,但输入的结果例如4
line in
(((5&4)==1)) && echo YES || echo NO
would print NO, even though one would expect YES in that case as well, as 4
and 5
both have the 3rd bit set.
将打印NO,即使一个会是期望在该情况下,作为4
与5
两者有第3位集。
So thisanswer addresses this logicalerror in the questions example and attempts an general answer the the question's headline.
所以这个答案解决了问题示例中的这个逻辑错误,并尝试对问题的标题做出一般性的回答。
First things first!
第一件事!
... or: "The Background of Bitwise Representation"
...或:“按位表示的背景”
to understand bitwise comparison it is helpful to visualise numbers in their bit representation (listed top-down in the following example):
|-----------------------------------------------------------| | | hexadecimal representation of the value | | bit val | 0 1 2 3 4 5 6 7 8 9 A B C D E F | |---------|---------------------- bit ----------------------| | | shows if the given value has the given bit set | | 0 | - x - x - x - x - x - x - x - x | | 1 | - - x x - - x x - - x x - - x x | | 2 | - - - - x x x x - - - - x x x x | | 3 | - - - - - - - - x x x x x x x x | |---------|---------------------- val ----------------------| | shows the value that the given bit adds to the number | | 0 1 | 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 | | 1 2 | 0 0 2 2 0 0 2 2 0 0 2 2 0 0 2 2 | | 2 4 | 0 0 0 0 4 4 4 4 0 0 0 0 4 4 4 4 | | 3 8 | 0 0 0 0 0 0 0 0 8 8 8 8 8 8 8 8 | |---------|-------------------------------------------------| |sum: 15 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | | | decimal representation of the value | |===========================================================|
要理解按位比较,在位表示中可视化数字是有帮助的(在以下示例中自上而下列出):
|-----------------------------------------------------------| | | hexadecimal representation of the value | | bit val | 0 1 2 3 4 5 6 7 8 9 A B C D E F | |---------|---------------------- bit ----------------------| | | shows if the given value has the given bit set | | 0 | - x - x - x - x - x - x - x - x | | 1 | - - x x - - x x - - x x - - x x | | 2 | - - - - x x x x - - - - x x x x | | 3 | - - - - - - - - x x x x x x x x | |---------|---------------------- val ----------------------| | shows the value that the given bit adds to the number | | 0 1 | 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 | | 1 2 | 0 0 2 2 0 0 2 2 0 0 2 2 0 0 2 2 | | 2 4 | 0 0 0 0 4 4 4 4 0 0 0 0 4 4 4 4 | | 3 8 | 0 0 0 0 0 0 0 0 8 8 8 8 8 8 8 8 | |---------|-------------------------------------------------| |sum: 15 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | | | decimal representation of the value | |===========================================================|
which is created by the following snippet:
这是由以下代码段创建的:
( # start a subshell to encapsulate vars for easy copy-paste into the terminal
# do not use this in a script!
echo ;
echo "|-----------------------------------------------------------|";
echo "| | hexadecimal representation of the value |";
echo "| bit val | 0 1 2 3 4 5 6 7 8 9 A B C D E F |";
echo "|---------|---------------------- bit ----------------------|";
echo "| | shows if the given value has the given bit set |";
mask=0;
for (( bit=0; bit<4; bit++)); do
mask=$((1<<bit));
echo -n "| $bit |"
for ((x=0;x<16;x++)); do ((((x&mask)>0))&&echo -n ' x'||echo -n ' -'); done
echo " |";
done ;
echo "|---------|---------------------- val ----------------------|";
echo "| shows the value that the given bit adds to the number |";
mask=0;
for (( bit=0; bit<4; bit++)); do
mask=$((1<<bit));
echo -n "| $bit $mask |"
for ((x=0;x<16;x++)); do echo -n " $((x&mask))"; done
echo " |";
done ;
echo "|---------|-------------------------------------------------|";
echo "|sum: 15 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |";
echo "| | decimal representation of the value |";
echo "|===========================================================|";
echo ;
)
The curious case of 3 & 5
vs 4 & 5
3 & 5
vs的奇怪案例4 & 5
... or: "==1
vs >0
and the Differences of &
, |
, and ^
"
...或者:“ ==1
VS>0
和的差异&
,|
以及^
”
if we now check the special case of the examples mentioned, we'll see the shortcoming:
|------------------ value: 3 / mask: 5 -------------------| | | value | mask | and | or | xor | xnor | | | 3 | 5 | 3 & 5 | 3 | 5 | 3 ^ 5 | | | bit val |bit:val|bit:val|bit:val|bit:val|bit:val|bit:val| |---------|-------|-------|-------|-------|-------|-------| | 0 1 | 1 1 | 1 1 | 1 1 | 1 1 | 0 0 | 0 0 | | 1 2 | 2 1 | 0 0 | 0 0 | 1 2 | 1 2 | 1 2 | | 2 4 | 0 0 | 4 1 | 0 0 | 1 4 | 1 4 | 1 4 | | 3 8 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | |---------|-------|-------|-------|-------|-------|-------| |sum: | 3 | 5 | ==> 1 | 7 | 6 | 6 | |---------|-----------------------------------------------| |check: | 3 & 5 == 1 ? YES | | | | 3 & 5 >= 1 ? YES | ==> 3 & 5 > 0 ? YES | |=========================================================| |------------------ value: 4 / mask: 5 -------------------| | | value | mask | and | or | xor | xnor | | | 4 | 5 | 4 & 5 | 4 | 5 | 4 ^ 5 | | | bit val |bit:val|bit:val|bit:val|bit:val|bit:val|bit:val| |---------|-------|-------|-------|-------|-------|-------| | 0 1 | 0 0 | 1 1 | 0 0 | 1 1 | 1 1 | 1 1 | | 1 2 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | | 2 4 | 4 1 | 4 1 | 1 4 | 1 4 | 0 0 | 0 0 | | 3 8 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | |---------|-------|-------|-------|-------|-------|-------| |sum: | 4 | 5 | ==> 4 | 5 | 1 | 1 | |---------|-----------------------------------------------| |check: | 4 & 5 == 1 ? NO | | | | 4 & 5 >= 1 ? YES | ==> 4 & 5 > 0 ? YES | |=========================================================|
如果我们现在检查提到的例子的特殊情况,我们会看到缺点:
|------------------ value: 3 / mask: 5 -------------------| | | value | mask | and | or | xor | xnor | | | 3 | 5 | 3 & 5 | 3 | 5 | 3 ^ 5 | | | bit val |bit:val|bit:val|bit:val|bit:val|bit:val|bit:val| |---------|-------|-------|-------|-------|-------|-------| | 0 1 | 1 1 | 1 1 | 1 1 | 1 1 | 0 0 | 0 0 | | 1 2 | 2 1 | 0 0 | 0 0 | 1 2 | 1 2 | 1 2 | | 2 4 | 0 0 | 4 1 | 0 0 | 1 4 | 1 4 | 1 4 | | 3 8 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | |---------|-------|-------|-------|-------|-------|-------| |sum: | 3 | 5 | ==> 1 | 7 | 6 | 6 | |---------|-----------------------------------------------| |check: | 3 & 5 == 1 ? YES | | | | 3 & 5 >= 1 ? YES | ==> 3 & 5 > 0 ? YES | |=========================================================| |------------------ value: 4 / mask: 5 -------------------| | | value | mask | and | or | xor | xnor | | | 4 | 5 | 4 & 5 | 4 | 5 | 4 ^ 5 | | | bit val |bit:val|bit:val|bit:val|bit:val|bit:val|bit:val| |---------|-------|-------|-------|-------|-------|-------| | 0 1 | 0 0 | 1 1 | 0 0 | 1 1 | 1 1 | 1 1 | | 1 2 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | | 2 4 | 4 1 | 4 1 | 1 4 | 1 4 | 0 0 | 0 0 | | 3 8 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | 0 0 | |---------|-------|-------|-------|-------|-------|-------| |sum: | 4 | 5 | ==> 4 | 5 | 1 | 1 | |---------|-----------------------------------------------| |check: | 4 & 5 == 1 ? NO | | | | 4 & 5 >= 1 ? YES | ==> 4 & 5 > 0 ? YES | |=========================================================|
Please pay particular attention to the following checks:
请特别注意以下检查:
|---------|-----------------------------------------------| |check: | 3 & 5 == 1 ? YES | | | | 3 & 5 >= 1 ? YES | ==> 3 & 5 > 0 ? YES | ---------|------------------------------------------------| |check: | 4 & 5 == 1 ? NO | | | | 4 & 5 >= 1 ? YES | ==> 4 & 5 > 0 ? YES | |---------|-----------------------------------------------|
|---------|-----------------------------------------------| |check: | 3 & 5 == 1 ? YES | | | | 3 & 5 >= 1 ? YES | ==> 3 & 5 > 0 ? YES | ---------|------------------------------------------------| |check: | 4 & 5 == 1 ? NO | | | | 4 & 5 >= 1 ? YES | ==> 4 & 5 > 0 ? YES | |---------|-----------------------------------------------|
The output above is created by the following snippet:
上面的输出由以下代码段创建:
( # start a sub-shell to encapsulate vars for easy copy-paste into the terminal
# do not use this in a script!
echo ;
for o in 3 4; do
echo "|------------------ value: $o / mask: 5 -------------------|";
echo "| | value | mask | and | or | xor | xnor |";
echo "| | $o | 5 | $o & 5 | $o | 5 | $o ^ 5 | |";
echo "| bit val |bit:val|bit:val|bit:val|bit:val|bit:val|bit:val|";
echo "|---------|-------|-------|-------|-------|-------|-------|";
mask=0;
for (( bit=0; bit<4; bit++)); do
mask=$((1<<bit));
echo -n "| $bit $mask "
echo -n " | $(($o&mask)) $((($o&mask)>0))"
echo -n " | $((5&mask)) $(((5&mask)>0))"
echo -n " | $(((($o&mask)&(5&mask))>0)) $((($o&mask)&(5&mask)))"
echo -n " | $(((($o&mask)|(5&mask))>0)) $((($o&mask)|(5&mask)))"
echo -n " | $(((($o&mask)^(5&mask))>0)) $((($o&mask)^(5&mask)))"
echo -n " | $(((($o&mask)^(5&mask))>0)) $((($o&mask)^(5&mask)))"
echo " |";
done ;
echo "|---------|-------|-------|-------|-------|-------|-------|";
echo -n "|sum: | $o | 5 |";
echo " ==> $(($o&5)) | $(($o|5)) | $(($o^5)) | $(($o^5)) |";
echo "|---------|-----------------------------------------------|";
echo -n "|check: | $o & 5 == 1 ? $(((($o&5)==1))&&echo YES||echo "NO ") ";
echo "| |";
echo -n "| | $o & 5 >= 1 ? $(((($o&5)>=1))&&echo YES||echo "NO ") ";
echo "| ==> $o & 5 > 0 ? $(((($o&5)>0))&&echo YES||echo "NO ") |";
echo "|=========================================================|";
echo ;
done
echo ;
)
Hello World!
你好,世界!
... or: "Rise and Shine!"
……或:“崛起并闪耀!”
So how do we do it now?! Let's imagine, we have the following option set:
# option set: option_1=1 option_2=2 option_3=4 option_4=8 option_5=16 option_6=32 option_7=64 option_8=128 option_9=256
We could for example set a selection of those options in a function and return the combined code as a return value. Or the other way round: pass a selection of options as one numeric parameter. Whatever your use case is, the options would be summed together:# set options: option = option_1 + option_4 + option_5 + option_9
How do we best check, which options are set (1
,4
,5
, &9
)? It depends of course again on your use case, but i kinda like thecase
construct! Something like ...case $option in 0) echo "no option set!";; 1) echo "option 1";; 2) echo "option 2";; 3) echo "option 1 and 2";; *) echo "...";; esac
could work, but is not very nice, as we would have to construct every combination!
那我们现在怎么办?!让我们想象一下,我们有以下选项集:
# option set: option_1=1 option_2=2 option_3=4 option_4=8 option_5=16 option_6=32 option_7=64 option_8=128 option_9=256
例如,我们可以在函数中设置这些选项的选择,并将组合代码作为返回值返回。或者反过来:将一组选项作为一个数字参数传递。无论您的用例是什么,这些选项都将汇总在一起:# set options: option = option_1 + option_4 + option_5 + option_9
我们如何最好地检查设置了哪些选项(1
,4
,5
, &9
)?这当然再次取决于您的用例,但我有点喜欢这种case
构造!就像是 ...case $option in 0) echo "no option set!";; 1) echo "option 1";; 2) echo "option 2";; 3) echo "option 1 and 2";; *) echo "...";; esac
可以工作,但不是很好,因为我们必须构建每个组合!
And the winner is ...
最终获胜者是 ...
... or: "The Real Case
"
......或:“真实的Case
”
We can use
case
in the following way instead ...echo "check for options using >0:" case 1 in $(( (option & option_1) >0 )) ) echo "- option_1 is set";;& $(( (option & option_2) >0 )) ) echo "- option_2 is set";;& $(( (option & option_3) >0 )) ) echo "- option_3 is set";;& $(( (option & option_4) >0 )) ) echo "- option_4 is set";;& $(( (option & option_5) >0 )) ) echo "- option_5 is set";;& $(( (option & option_6) >0 )) ) echo "- option_6 is set";;& $(( (option & option_7) >0 )) ) echo "- option_7 is set";;& $(( (option & option_8) >0 )) ) echo "- option_8 is set";;& $(( (option & option_9) >0 )) ) echo "- option_9 is set";;& esac
Please notethat
- the spaces within
$(( (option & option_1) >0 )) )
are completely optional and are added for readability. The last closing bracket)
is for thecase
construct.- the command-lists are terminated with
;;&
, in order to continue evaluation with the next option test. In case you want to abord further processing of the list, setoption=0
or to your currentoption=option_X
.... we get the following result:
check for options using >0: - option_1 is set - option_4 is set - option_5 is set - option_9 is set
Hurray! :-)
我们可以通过
case
以下方式使用...echo "check for options using >0:" case 1 in $(( (option & option_1) >0 )) ) echo "- option_1 is set";;& $(( (option & option_2) >0 )) ) echo "- option_2 is set";;& $(( (option & option_3) >0 )) ) echo "- option_3 is set";;& $(( (option & option_4) >0 )) ) echo "- option_4 is set";;& $(( (option & option_5) >0 )) ) echo "- option_5 is set";;& $(( (option & option_6) >0 )) ) echo "- option_6 is set";;& $(( (option & option_7) >0 )) ) echo "- option_7 is set";;& $(( (option & option_8) >0 )) ) echo "- option_8 is set";;& $(( (option & option_9) >0 )) ) echo "- option_9 is set";;& esac
请注意的是
- 里面的空格
$(( (option & option_1) >0 )) )
是完全可选的,并且是为了可读性而添加的。最后一个右括号)
用于case
构造。- 在命令列表s的终止
;;&
,以继续评估下一个选项测试。如果您想放弃对列表的进一步处理,请将option=0
或设置为您当前的option=option_X
....我们得到以下结果:
check for options using >0: - option_1 is set - option_4 is set - option_5 is set - option_9 is set
欢呼!:-)
And if
I was a rich man!
而且if
我还是个有钱人!
echo "# to use it in an if statement:"; if (((option&option_5)>0)); then echo "- option_5 is set" else echo "- option_5 is NOT set" fi # to use it in an if statement: - option_5 is set
echo "# to use it in an if statement:"; if (((option&option_5)>0)); then echo "- option_5 is set" else echo "- option_5 is NOT set" fi # to use it in an if statement: - option_5 is set
But finally the poor man's condition:
但最后是穷人的状况:
echo "# or to use it just for conditional execution:"; (((option&option_6)>0)) \ && echo "- option_6 is set" \ || echo "- option_6 is NOT set" # or to use it just for conditional execution: - option_6 is NOT set
echo "# or to use it just for conditional execution:"; (((option&option_6)>0)) \ && echo "- option_6 is set" \ || echo "- option_6 is NOT set" # or to use it just for conditional execution: - option_6 is NOT set
"He who does not answer the questions has passed the test."
“不回答问题的人通过了测试。”
... or: 'Stay,' he said, 'that was only a test.'
……或者:“留下来,”他说,“那只是一个考验。”
(Kafka, 1975: 181)
(卡夫卡,1975:181)
So it would be perfectly possible to use the solution as posted in the question, by the slight change as follows:
( declare -A releases=([token]=4) declare -i MASK=5 if [[ $(( releases["token"] & $MASK )) -gt 0 ]]; then echo YES else echo NO fi )
The changes are the following: - use
$(())
instead of()
to do the test, which will return the value of the bitwise comparison - use-gt 0
instead of-eq 1
因此,完全可以使用问题中发布的解决方案,只需稍作更改,如下所示:
( declare -A releases=([token]=4) declare -i MASK=5 if [[ $(( releases["token"] & $MASK )) -gt 0 ]]; then echo YES else echo NO fi )
更改如下: - 使用
$(())
代替进行()
测试,这将返回按位比较的值 - 使用-gt 0
代替-eq 1
altogether in action:
完全在行动:
( # start a sub-shell to encapsulate vars for easy copy-paste into the terminal
# do not use this in a script!
echo ;
for ((i=0; i<9;i++)); do
o="option_$((i+1))"
declare -i $o=$((1<<$i))
echo "$o = ${!o}"
done
echo ;
echo ;
echo "# set options:"
echo "option = option_1"
echo " + option_4"
echo " + option_5"
echo " + option_9"
option=option_1+option_4+option_5+option_9
echo ;
echo ;
echo "check for options using >0:"
case 1 in
$(( (option & option_1) >0 )) ) echo "- option_1 is set";;&
$(( (option & option_2) >0 )) ) echo "- option_2 is set";;&
$(( (option & option_3) >0 )) ) echo "- option_3 is set";;&
$(( (option & option_4) >0 )) ) echo "- option_4 is set";;&
$(( (option & option_5) >0 )) ) echo "- option_5 is set";;&
$(( (option & option_6) >0 )) ) echo "- option_6 is set";;&
$(( (option & option_7) >0 )) ) echo "- option_7 is set";;&
$(( (option & option_8) >0 )) ) echo "- option_8 is set";;&
$(( (option & option_9) >0 )) ) echo "- option_9 is set";;&
esac
echo ;
echo ;
echo "# to use it in an if statement:";
echo " => if (((option&option_5)>0));";
if (((option&option_5)>0)); then
echo "- option_5 is set"
else
echo "- option_5 is NOT set"
fi
echo ;
echo ;
declare -A releases=([token]=4)
declare -i MASK=5
echo "# Does 4 pass the mask 5 in the test construct?";
echo " => if [[ $(( releases["token"] & $MASK )) -gt 0 ]];";
if [[ $(( releases["token"] & $MASK )) -gt 0 ]]; then
echo YES
else
echo NO
fi
echo ;
echo ;
echo "# or to use it just for conditional execution:";
echo " => (((option&option_6)>0)) && do || dont";
(((option&option_6)>0)) \
&& echo "- option_6 is set" \
|| echo "- option_6 is NOT set"
)
The End
结束
Exit 0
回答by Gustavo
In if statement:
在 if 语句中:
if (((releases["token"] & $MASK) == 1)); then
echo YES
else
echo NO
fi