正则shell /bin/sh(非bash)支持位运算符吗?

3

我在使用/bin/sh中的位运算符&时遇到了错误。虽然我可以在bash中使其正常工作,但将执行代码的脚本在常规shell中启动,因此我需要在纯常规shell中使其正常工作。我只需检查某个位是否设置,例如第7位。

以下代码在bash中有效,但在/bin/sh中无效:

#!/bin/bash
y=93
if [ $((($y & 0x40) != 0)) ]; then
  echo bit 7 is set
fi

我尝试在/bin/sh中去除算术扩展,如上所示。

#!/bin/sh
y=93
val=`expr $y & 0x40`
if [ $val != 0 ]; then
   echo worked 1
fi

有人能否建议如何在普通的shell中使用按位运算符?

sh 不支持位移操作。 - Inian
注意:“位 7”通常被认为是 MSB,例如具有掩码“0x80”的位,而“位 0”则是 LSB。 - Alnitak
/bin/sh 可以是 POSIX sh(早期 1990 年代标准)或 Bourne shell(1970 年代实现)。特别是在 Solaris 上,这两者在现代时代都存在(如果后者在 /bin 中,则前者通常在 /usr/xpg/bin 中);$(( )) 仅存在于前者中。你知道你使用的是哪个吗? - Charles Duffy
1
顺便提一下,POSIX expr 支持 &,但它被 POSIX 定义为布尔逻辑运算符,而不是位运算符。即使以这种方式工作,您也需要对其进行转义:expr "$i" '&' 64; 在您原始代码的未转义情况下,& 告诉 shell 将其左侧的所有内容放到自己的命令中在后台运行(然后尝试将右侧的内容解析为另一个单独的命令,因此它将0x40作为命令运行,并将该命令的输出捕获到名为 val 的变量中...因此导致了原始代码的失败)。 - Charles Duffy
1
@CharlesDuffy - 感谢您澄清POSIX和Bourne之间的区别。由于它打印了“hello”,所以我有Bourne shell。 - YS_NE
显示剩余2条评论
3个回答

4

您可以使用除法和取模运算来检查特定位:

if [ `expr \( $y / 64 \) % 2` -eq 1 ]; then
  echo bit 6 is set
fi

2
在 POSIX sh 中,“==”不能保证在“[中被支持,也不支持“[的早期 POSIX 实现。如果您想要兼容性,请使用“=”(用于字符串比较)或“-eq”(用于数字比较)。 - Charles Duffy
@CharlesDuffy 是的,我实际上没有旧的非bash /bin/sh来进行测试。 - Alnitak
@CharlesDuffy 我认为现在应该在任何版本的 sh 上运行。 - Alnitak
1
我也这么认为。我有点讨厌时代错误(在确认 OP 真的是在使用 pre-POSIX Bourne 之前,我不会给予支持),但是找不到任何正确性错误(除了命令替换周围缺少双引号,这只是吹毛求疵——只有当 expr 失败或 IFS 包含 01 时,它才会造成可达到的错误)。 - Charles Duffy
@Alnitak的转换为除法和取模似乎使它与我所使用的Shell兼容。算术展开只能在有限的Shell中使用。非常感谢。 - YS_NE

2

我认为问题在于您正在使用算术扩展返回的字符串,而不是退出代码。您可能应该在外部执行等于 0 的测试,例如:

if [ "$((y & 0x40))" -ne 0 ]; then

否则,$(((y & 0x40) != 0))将返回一个字符串,它将始终非空,因此真实性测试将始终通过。

3
POSIX规定了在POSIX sh标准中引用的算术运算符集合中的&,因此如果操作者处理的是POSIX sh而不是Bourne,则应该确实可以使用。 - Charles Duffy
不幸的是,Solaris在最近几十年中都有发行版,因此我们需要从OP那里得到澄清,确切地了解他们正在运行哪个实现版本,以确定这个答案是否适用。 - Charles Duffy
我差点就说最好将常量从十六进制转换为十进制以确保安全,但是仔细查看POSIX sh算术标准后发现,十六进制常量也是POSIX sh所必需的行为,因此我们在这里真的处于一个良好的状态,除非OP正在使用Bourne。 - Charles Duffy
@CharlesDuffy 看起来原帖使用的是普通的 Bourne Shell,而不是 POSIX。 - Alnitak
@Alnitak,是的,我今天早上就看到了,我承诺的点赞也在那时候完成了。 - Charles Duffy

0

根据Alnitak的回答,我会这样做:

if expr \( $y / 128 \) % 2 > /dev/null; then
  echo bit 7 is set
fi

这只是更加简洁的表述。

请注意:2^7=128


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接