16

我想写这样的东西:

if [[ ( releases["token"] & $MASK ) -eq 1 ]]; then

但我得到的错误是:

意外标记“&”,应为条件二元运算符

如何在 if 语句中使用位运算符?

4

3 回答 3

27

您可以使用Arithmetic Expansion

(((5&3)==1)) && echo YES || echo NO

它会打印YES

于 2013-01-14T12:51:33.727 回答
27

逻辑与语法

.... 或者:“还有什么要说的?”

乍一看,正如@chepner 的评论中指出的那样,问题可能只是语法之一,这会导致编译错误(unexpected token '&', conditional binary operator expected)。事实上,@kev 的答案通过使用算术扩展来解决这个问题,这适用于@Gustavo 的答案If中的语句 。

然而,如何在 if 语句中使用按位运算符”的问题以更一般的方式表述,并寻求关于如何使用按位运算符进行检查的答案$MASK(这不是“如何避免语法错误的问题”使用二进制比较”)。

实际上,可以假设示例代码

if [[ ( releases["token"] & $MASK ) -eq 1 ]]; then

是一项正在寻找解决方案的工作,并被明确标记为“类似......”。现在@kev 的任意假设

 releases["token"]=3
 MASK=5

可能会隐藏一个事实,即在使用中也存在逻辑上的误解-eq 1。因此,虽然@kev 的答案适用于所选值,但输入例如4line in

 (((5&4)==1)) && echo YES || echo NO

会打印NO,即使在这种情况下也会期望 YES ,因为4两者5都设置了第 3 位。

因此,答案解决了问题示例中的此逻辑错误,并尝试对问题的标题进行一般性回答。


最重要的事情!

...或:“按位表示的背景”

要理解按位比较,以位表示形式可视化数字会很有帮助(在以下示例中自上而下列出):

|-----------------------------------------------------------|
|         |     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       |
|===========================================================|

它由以下代码段创建:

( # 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 ;
)


3 & 5vs的奇怪案例4 & 5

... 或:“==1与、和>0的区别”&|^

如果我们现在检查所提到示例的特殊情况,我们将看到缺点:

|------------------ 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  |
|=========================================================|


请特别注意以下检查:

|---------|-----------------------------------------------|
|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  |
|---------|-----------------------------------------------|


上面的输出由以下代码段创建:

( # 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 ;
)


你好世界!

...或:“崛起和闪耀!”

那么我们现在该怎么做呢?!让我们想象一下,我们有以下选项集:

# 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

可以工作,但不是很好,因为我们必须构建每个组合!


最终获胜者是 ...

……或者:“真实的Case

我们可以改用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构造。
  • command-list以, 结尾 ;;&,以便继续使用下一个选项测试进行评估。如果您想中止对列表的进一步处理,请将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

欢呼!:-)


而且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 "# 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


“不回答问题的人已经通过了测试。”

……或者:“留下来,”他说,“那只是一个考验。”

(卡夫卡,1975:181)

因此,完全有可能使用问题中发布的解决方案,只需稍作改动如下:

(
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


完全在行动:

( # 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"

)


结束

Exit 0
于 2016-03-11T04:37:55.493 回答
4

在 if 语句中:

if (((releases["token"] & $MASK) == 1)); then 
  echo YES
else 
  echo NO
fi
于 2014-05-28T16:33:38.677 回答