在shell脚本中将十进制数转换为十六进制和二进制

4

我有一个 file.txt 文件,每行都是一个十进制数:

    1
    2
    3

我尝试(已经很长时间了)编写一个一行脚本,以便输出每行都有十进制、十六进制和二进制的列。为了简化任务,我们可以假设原始数字是用一个字节表示的。因此,最大值是255。

  1. I first try to decode each number as a bynary with prepended 0 so to have an 8 bits pattern:

    awk '{print "ibase=10;obase=2;" $1}' $1 | bc | xargs printf "%08d\n"

    where the outer $1 in the awk statement is file.txt. The output is :

    00000001
    00000010
    00000011
    
  2. Same for hex with one prepended 0

    awk '{printf("0x%02x\n", $1)}' $1

    Same as before. The Output is :

    0x01
    0x02
    0x03
    
  3. Well, the decimal should be just a print:

    1
    2
    3
    
我希望你能提供一句话的翻译,其中包括以下内容:

我想要的是一行代码:

    1 00000001 0x01
    2 00000001 0x02

基本上,要在输出的每一行中放置1、2和3。

我尝试使用system()在awk中执行bc(和其他命令),但没有成功。还有其他无数种方法。你会怎么做?


对于十六进制,您可以使用:printf "%X" 15,它将返回 F - fedorqui
@fedorqui 我想要一个固定宽度的十六进制数。因此我选择0x%02x,其中%02x表示两位数字(或者我这样认为)。大写字母X只会将其转换为大写。 - splinux
3个回答

8
以下一行代码应该可以正常运行:
printf "%s %08d 0x%02x\n" "$1" $(bc <<< "ibase=10;obase=2;$1") "$1"

示例输出:

$ for i in {1..10}; do printf "%s %08d 0x%02x\n" "$i" $(bc <<< "ibase=10;obase=2;$i") "$i"; done
1 00000001 0x01
2 00000010 0x02
3 00000011 0x03
4 00000100 0x04
5 00000101 0x05
6 00000110 0x06
7 00000111 0x07
8 00001000 0x08
9 00001001 0x09
10 00001010 0x0a

6

所以,我搜索了一个简短而优雅的awk二进制转换器。不满意的话可以当作一种挑战,那么现在你就有了。稍微进行了一些尺寸优化,因此我下面放了一个可读版本。

末尾的printf指定数字的大小。在本例中是8位。

这是糟糕的代码吗?嗯,是的...它是awk :-) 当然无法处理非常庞大的数字。

67个字符长的awk代码:

awk '{r="";a=$1;while(a){r=((a%2)?"1":"0")r;a=int(a/2)}printf"%08d\n",r}'

编辑:55个字符的awk代码

awk '{r="";a=$1;while(a){r=a%2r;a=int(a/2)}printf"%08d\n",r}'

易读版本:

awk '{r=""                    # initialize result to empty (not 0)
      a=$1                    # get the number
      while(a!=0){            # as long as number still has a value
        r=((a%2)?"1":"0") r   # prepend the modulos2 to the result
        a=int(a/2)            # shift right (integer division by 2)
      }
      printf "%08d\n",r       # print result with fixed width
     }'

关于二进制和十六进制的简短说明:

awk '{r="";a=$1;while(a){r=a%2r;a=int(a/2)}printf"%08d 0x%02x\n",r,$1}'

4
您不需要使用 bc。这里有一个只使用 awk 的解决方案:
  • Fetch the bits2str function available in the manual
  • Add this minimal script:

    {
        printf("%s %s %x\n", $1, bits2str($1), $1)
    }
    
这会产生以下结果:
$ awk -f awkscr.awk nums 
1 00000001 1
2 00000010 2
3 00000011 3

虽然非常正确,但我需要引入一个函数并打破一行代码的限制。使用awk加1分。 - splinux
@splinux 哦,我错过了单行要求,对此感到抱歉。不过还是谢谢你,希望能帮助到其他人 :-) - cnicutar
将数字转换为固定长度二进制的<80个字符一行代码 - Gunstick

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