【问题标题】:bash: how do I convert a hex subnet mask into bit form or the dot-decimal address?bash:如何将十六进制子网掩码转换为位形式或点十进制地址?
【发布时间】:2018-05-24 14:22:16
【问题描述】:

到目前为止,我的代码将从 iOS 系统获取 IP 地址和十六进制形式的子网掩码 (ffffff00),但我需要位形式(24、23 等)或二进制形式的子网地址。我该怎么做?我尝试使用16#${subnet} 转换它,但数字似乎错误。

有点愚蠢的问题——如果echo "hello" 行被删除并且我不确定为什么,代码不会运行?那条线起什么作用?

if [ $# -ne 0 ]
    echo "hello"
    then
        ip="$(ifconfig | grep "inet " | grep -v 127.0.0.1 | cut -d\  -f2)"
        subnet="$(ifconfig | grep "netmask " | grep -v 0xff0 | sed -e 's/.*0x\(.*\)broadcast.*/\1/')"
        consub="$((16#${subnet}))"
        echo "$ip $subnet $consub"
exit 0
fi

【问题讨论】:

  • if (condition) ; then 是常用语法。 echo 是一个语句,允许您出于愚蠢的原因跳过;
  • 另外,如果您正在编写不需要 POSIX 可移植性的 bash 脚本,请考虑使用 [[ .. ]] 而不是 [ .. ]
  • @hack,你能不能add to your question 你得到的结果,以及你想看到的结果?这将有助于评估我们为创建答案所做的工作。你的问题是一个很好的开始。如果它包含MCVE,那就更好了。

标签: bash ip-address subnet


【解决方案1】:

怎么样:

echo "ffffff00" | perl -pe '$_ = join(".", map(hex, /.{2}/g))'
=> 255.255.255.0

echo "ffffff00" | perl -pe '$_ = unpack("B32", pack("H*", $_)); s/0+$//g; $_ = length'
=> 24

【讨论】:

    【解决方案2】:

    没有一种可靠的方法可以预测在运行 bash 的系统中您手头将拥有什么计算器(您可能有 bc 或 dc 或其他东西),但您并不真的需要这些。考虑以下函数:

    binary () {
        local n bit=""
        printf -v n '%d' "$1"
        for (( ; n>0 ; n >>= 1 )); do  bit="$(( n&1 ))$bit"; done
        printf '%s\n' "$bit"
    }
    

    这使用>>= 对输入数字进行按位移动,然后使用n&1 对数字中的该位置进行按位与运算,并将结果插入$bit 以进行最终输出。

    你可以输入任何数字:

    $ binary 123
    1111011
    $ binary 0xffffff00
    11111111111111111111111100000000
    

    从那里,您应该能够简单地计算您的数量:

    $ netmask="0xffffff00"
    $ bitmask=$( s=$(binary "$netmask"); s="${s%%0*}"; printf '%d' "${#s}" )
    $ echo "$bitmask"
    24
    

    【讨论】:

    • 抱歉延迟回复,但这看起来真的很接近我正在寻找的!你介意解释一下这里正在做什么for (( ; n>0 ; n >>= 1 )); do bit="$(( n&1 ))$bit"; done - 我仍然对 bash 语法感到不安,我一直在尝试通读手册,但它到底是什么循环与 ; n>0 ; n >>= 1$(( n&1 ))$bit 做什么?能帮忙解释一下位掩码功能吗?
    • 我正在尝试查找语法并阅读相关内容,但无法将各个部分拼凑在一起。
    • 对于 for 循环表示法,在 bash 手册页中搜索 for ((。然后检查“算术扩展”下的手册页。要查看 AND 的作用,请尝试:for n in {1..5}; do echo $((n&1)); done。对于任何奇数,AND 返回“1”。 (1 && 1 == 1.)
    • 至于“单步执行”部分...... for 循环将您的号码从 LSB 传递到 MSB,对每一位进行与运算。请参阅:x=5; for ((n=$x; n>0; n>>=1)); do echo $((n&1)); done>>= 只是意味着值中的所有位都向右移动,使下一位成为 LSB。 Bash Hackers Wiki 有更多信息。你可能想谷歌“位移”。
    • 哦,“位掩码”是您要询问的数字的术语——网络的有效位数。所以0xfffe0000 的网络掩码是十进制的255.254.0.0,可以表示为15 的位掩码,用于CIDR 表示法。
    【解决方案3】:

    您可以使用现代 iproute2 工具来获取 CIDR,而不是解析 ifconfig。例如:

    ip -f inet -o a s scope global |
        grep -Po 'inet \S+' |
        sed 's#.*/\(.*\)#\1#'
    

    【讨论】:

    • 我尝试了其他 ip 命令,但一直收到错误消息,提示我没有 ip 命令。
    • @hack 老实说,在这种情况下,我建议您找出默认情况下可用的脚本语言,并在其中编写一些小东西,以便以您想要的格式输出网络掩码。你可以用很多 bash 来做到这一点,但它会变得非常丑陋 :( 就像:为f, e, c, 8, 0 映射到未设置的位数并总结整个网络掩码以获得一种丑陋的 CIDR .
    • 虽然我讨厌批评任何促进使用 sed 的东西,但 OP 提到这是在 iOS 中运行的,所以 ipiproute2 都出局了。似乎 bash 中的一些小东西正是 OP 所要求的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-01
    • 2020-08-08
    • 1970-01-01
    • 2017-03-08
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    相关资源
    最近更新 更多