添加两个十六进制数字并在shell脚本中存储为十六进制数字

问题描述 投票:1回答:2

我试图在shell脚本中添加两个十六进制数字并将结果存储为十六进制数字。

let "step_size = 10"
let "start_num = 20000000"
let "size = 64"
for (( i = 0; i < 1000; i = $i + $step_size ))
do
    for (( j = 0; j < $step_size; j++ ))
    do
        let "temp = $(( $(( $i * $step_size)) + $(( $j * $size )) ))"
        num=`echo "obase=16; $temp" | bc`
        echo $num
        num2=`obase=16;ibase=16; echo $start_num \\+ $num | bc`
        echo $start_num $num $num2
        echo "****"
    done
done

并非所有结果都是错误的。我只有在$num = C0时才会收到错误

产量

0
20000000 0 20000000
****
40
20000000 40 20000040
****
80
20000000 80 20000080
****
C0
20000000 C0 20000090 #This is the error!!
****
100
20000000 100 20000100
****
...
...
...
1C0
20000000 1C0 20000190 #Error again!!

我正在使用zshell。我不确定为什么会这样。任何帮助都非常感谢。

谢谢

linux bash shell hex zsh
2个回答
1
投票

大概

num2=`obase=16;ibase=16; echo $start_num \\+ $num | bc`

应该

num2=`echo "obase=16;ibase=16;$start_num + $num" | bc`

你根本没有计算十六进制。

我还建议像这样的简化版本:

#!/bin/zsh

step_size=10
start_num=20000000
size=64

for (( i = 0; i < 1000; i += step_size )); do
    for (( j = 0; j < step_size; ++j )); do
        (( temp = (i * step_size) + (j * size) ))
        num=$(echo "obase=16; $temp" | bc)
        echo "$num"
        num2=$(echo "obase=16;ibase=16;$start_num + $num" | bc)
        echo "$start_num $num $num2"
        echo "****"
    done
done

它适用于Zsh和Bash。

# bash temp.zsh | head -20
0
20000000 0 20000000
****
40
20000000 40 20000040
****
80
20000000 80 20000080
****
C0
20000000 C0 200000C0
****
100
20000000 100 20000100
****
140
20000000 140 20000140
****
180
20000000 180 20000180

3
投票

@konsolebox有一个正确的修复,但我认为OP中显示的行为有点神秘,所以它似乎值得解释。

首先,很明显

num2=`obase=16;ibase=16; echo $start_num \\+ $num | bc`

是不正确的,因为它设置shell变量obaseibase而不是将赋值传递给bc。此外,没有必要引用+。但是为什么bc不会产生错误,因为如果该行以现代形式编写,它将会产生错误:

num2=$(obase=16;ibase=16; echo $start_num \\+ $num | bc)

答案是`…`$(…)之间存在细微差别:

% `echo echo \\+`
+
% $(echo echo \\+)
\+

引用bash manual

当使用旧式反引号形式的替换时,反斜杠保留其字面含义,除非后跟$,`或\。第一个不带反斜杠的反引号会终止命令替换。使用$(command)表单时,括号内的所有字符组成命令;没有人特别对待。

实际上,这意味着反引用版本解释了\-escape两次:首先扫描反引号字符串时,当\\+变为\+时,然后第二次解析结果命令时,\+变为+

第二个问题是“20000090来自哪里?”在这里答案是,这是bc解释数字的方式的一个奇怪的特征。值得引用man bc的完整段落(重点补充):

输入数字可能包含字符0-9A-F。 (注意:它们必须是大写字母。小写字母是变量名。)无论ibase的值如何,单个数字的数字始终具有数字的值。 (即A = 10。)对于多位数字,bc将大于或等于ibase的所有输入数字更改为ibase-1的值。这使得数字FFF始终是输入基数的最大3位数。

由于ibase没有设置在bc(见上文),bcC0解释为十进制90,尽管它会将C解释为十进制12


最后,使用bashzsh,以下工作正常,不需要bc

% a=20000000
% b=C0
% printf "%X\n" $((0x$a+0x$b))
200000C0
© www.soinside.com 2019 - 2024. All rights reserved.