Eps*_*tor 15 bash shell bit-manipulation
我想写这样的东西:
if [[ ( releases["token"] & $MASK ) -eq 1 ]]; then
Run Code Online (Sandbox Code Playgroud)
但我得到的错误是:
意外的令牌"&",预期的条件二元运算符
如何在if语句中使用按位运算符?
kev*_*kev 25
你可以使用Arithmetic Expansion:
(((5&3)==1)) && echo YES || echo NO
Run Code Online (Sandbox Code Playgroud)
它会打印YES
Mar*_*egg 23
乍一看,正如@Chepner的评论所指出的那样,问题可能只是语法之一,导致编译错误(unexpected token '&', conditional binary operator expected).实际上,@ kev的答案通过使用算术扩展来解决这个问题,该算法扩展应用于@ Gustavo答案中的If语句 .
但是," 如何在if语句中使用按位运算符 "的问题以更一般的方式表达,并请求如何使用按位运算符进行检查$MASK(这不是"如何避免语法错误时的问题"使用二进制比较").
实际上,可以假设示例代码
Run Code Online (Sandbox Code Playgroud)if [[ ( releases["token"] & $MASK ) -eq 1 ]]; then
是一项正在寻找解决方案的工作,并明确标记为"类似......".现在@kev的任意假设
releases["token"]=3
MASK=5
Run Code Online (Sandbox Code Playgroud)
可能会隐藏这样一个事实,即-eq 1首先使用时也存在逻辑上的误解.因此,虽然@kev的答案适用于所选择的值,但输入的结果例如是4line in
(((5&4)==1)) && echo YES || echo NO
Run Code Online (Sandbox Code Playgroud)
将打印NO,尽管人们所期望的是在该情况下,作为4与5两者有第3位集.
因此,这个答案解决了问题示例中的这个逻辑错误,并试图回答问题的标题.
要理解按位比较,有助于在其位表示中可视化数字(在下面的示例中自上而下列出):
Run Code Online (Sandbox Code Playgroud)|-----------------------------------------------------------| | | 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 ;
)
Run Code Online (Sandbox Code Playgroud)
3 & 5vs 的奇怪案例4 & 5==1VS >0和的差异&,|以及^"如果我们现在检查上述例子的特殊情况,我们会看到缺点:
Run Code Online (Sandbox Code Playgroud)|------------------ 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 | |=========================================================|
请特别注意以下检查:
Run Code Online (Sandbox Code Playgroud)|---------|-----------------------------------------------| |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 ;
)
Run Code Online (Sandbox Code Playgroud)
那我们现在怎么做呢?!让我们假设,我们有以下选项集:
Run Code Online (Sandbox Code Playgroud)# 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
例如,我们可以在函数中设置这些选项的选择,并将组合代码作为返回值返回.或者反过来:将选择的选项作为一个数字参数传递.无论您的用例是什么,选项都将汇总在一起:Run Code Online (Sandbox Code Playgroud)# set options: option = option_1 + option_4 + option_5 + option_9
我们如何最好检查一下,该选项设置(1,4,5,&9)?它当然取决于你的用例,但我有点像case构造!就像是 ...Run Code Online (Sandbox Code Playgroud)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以下方式代替......Run Code Online (Sandbox Code Playgroud)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....我们得到以下结果:
Run Code Online (Sandbox Code Playgroud)check for options using >0: - option_1 is set - option_4 is set - option_5 is set - option_9 is set欢呼!:-)
if我是一个有钱人!Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)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)
因此,完全有可能使用问题中公布的解决方案,稍作修改如下:
Run Code Online (Sandbox Code Playgroud)( 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"
)
Run Code Online (Sandbox Code Playgroud)
Exit 0
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
24495 次 |
| 最近记录: |