使用Shell脚本反转十六进制数

3

我想在Bash或其他shell中反转一个十六进制数。

比如,我要反转十六进制数4BF8E,答案应该是71FD2,即按位反转。


1
“reverse” 不是正确的词(我假设您指的是字节顺序)。您的意思是“反转”或“计算位求反”。 - Jonathon Reinhart
按位非 4BF8E = FD071 不是 71FD2,这是按位反转的结果。 - Steve Barnes
嗨,乔纳森,感谢您的快速回复。这里我只是指反转。十六进制数应该被转换为二进制,然后反转二进制位并转换回十六进制,得到的结果是 71FD2,是 4BF8E 的反转。 - OgANgA
反转位与否定绝对不是相同的操作。二进制数 00001011 反转后变成了 11010000,而取反后则是 11110100 - 这是两个完全不同的操作。反转位在快速傅里叶变换中非常有用(尽管为什么要在 bash 中编写 FFT 呢?),或者用于解码以不同顺序序列化为十六进制字符串的位数组。 - SF.
对于想在Bash中计算按位NOT的访问者,以0x2C8B为例:hex_nr=0x2C8B; hex_len=$(( ${#hex_nr} - 2 )); inverted=$(printf '%X' "$(( ~ hex_nr ))"); trunc_inverted=${inverted: -hex_len}; echo $trunc_inverted - Matthias Braun
5个回答

4
echo 4BF8E | rev | tr '0123456789ABCDEF' '084C2A6E195D3B7F'

解释:

  • rev 将4BF8E反转为E8FB4
  • tr 将每个十六进制值映射到它的位反转值

1
唯一的问题是尝试使用0x4BF8E作为输入 - 这是有效的十六进制,但存在问题,并且使用4bf8e时需要扩展tr。 - Steve Barnes

0
这是我想出来的一种非常高效且相对简单的方法:
[g/n/m]awk 'BEGIN { 
     
    ____=index(___="bits::[%.f]"\
              (_="\n")"%s"(_)_,".")

      __=index("_"(_="0|1|"),_)     

 do { gsub(/[^|]+[|]/,"0&1&",_)
      printf(___,__,_) 
    } while(++__<____) }'

它将为所有8位生成按顺序排序的位反射位字符串,输出如下:

bits::[2]
00|10|01|11|

bits::[3]
000|100|010|110|001|101|011|111|…

bits::[4]
0000|1000|0100|1100|0010|1010|0110|1110|0001|1001|0101|1101|0011|1011|0111|1111|

bits::[5]
00000|10000|01000|11000|00100|10100|01100|11100|00…

bits::[6]…
000000|100000|010000|110000|001000|101000|011000|1…

bits::[7]
0000000|1000000|0100000|1100000|0010000|1010000|01…

bits::[8]
00000000|10000000|01000000|11000000|00100000|10100…

只需执行7次do-while循环,您就可以获得所有256字节的反射,按其字节序值预先排序。

在4位级别上,这些位字符串确实对应于十六进制等效项084C 2A6E-195D-3B7F

[g/n/m]awk 'mawk2 '

BEGIN { ___=" bits : %2.f | combos :"\ 
            " %8.f | tot-len : %10.f\n"
          _="0|"(____="1")"|"    

           # specify max-bit-level
           # fail safe default to 8
           #
       ____=(____+=int( 24 ))<(__=3)?__*__:____;    
         __=index("_"_,_)
     do {                          
          gsub(/[^|]+[|]/,"0&1&",_) 
          printf(___,__,(_____=\ 
                length(_))/(++__),_____)  
                         
     } while (__<____) }'

 bits :  2 | combos :        4 | tot-len :         12
 bits :  3 | combos :        8 | tot-len :         32
 bits :  4 | combos :       16 | tot-len :         80

 bits :  5 | combos :       32 | tot-len :        192
 bits :  6 | combos :       64 | tot-len :        448
 bits :  7 | combos :      128 | tot-len :       1024
 bits :  8 | combos :      256 | tot-len :       2304

 bits :  9 | combos :      512 | tot-len :       5120
 bits : 10 | combos :     1024 | tot-len :      11264
 bits : 11 | combos :     2048 | tot-len :      24576
 bits : 12 | combos :     4096 | tot-len :      53248
 bits : 13 | combos :     8192 | tot-len :     114688
 bits : 14 | combos :    16384 | tot-len :     245760
 bits : 15 | combos :    32768 | tot-len :     524288
 bits : 16 | combos :    65536 | tot-len :    1114112

 bits : 17 | combos :   131072 | tot-len :    2359296
 bits : 18 | combos :   262144 | tot-len :    4980736
 bits : 19 | combos :   524288 | tot-len :   10485760
 bits : 20 | combos :  1048576 | tot-len :   22020096
 bits : 21 | combos :  2097152 | tot-len :   46137344
 bits : 22 | combos :  4194304 | tot-len :   96468992
 bits : 23 | combos :  8388608 | tot-len :  201326592
 bits : 24 | combos : 16777216 | tot-len :  419430400

就速度而言,

  • 高达8位/单字节:0.007秒
  • 高达16位/每2个字节组合:0.015秒
  • 高达24位/每3个字节组合:2.297秒

如果您想尝试更高位字符串组合级别,请确保您的系统能够处理:

 bits : 25 | combos :   33554432 | tot-len :   872415232
 bits : 26 | combos :   67108864 | tot-len :  1811939328
 bits : 27 | combos :  134217728 | tot-len :  3758096384

 bits : 28 | combos :  268435456 | tot-len :  7784628224
 bits : 29 | combos :  536870912 | tot-len : 16106127360
 bits : 30 | combos : 1073741824 | tot-len : 33285996544
 bits : 31 | combos : 2147483648 | tot-len : 68719476736

mawk2 354.61秒用户时间 44.08秒系统时间 88% cpu7:29.79 总共耗时

我不敢超过31位组合。那已经有

  • 21.4亿个二进制字符串组合,
  • 按位反转,
  • 按顺序排列
    • 一个长度为64.00 GB的单一字符串。

我的电脑花了约7.5分钟才完成这个任务。


0
一个Python解决方案(假设您需要字节对齐):
def bin(a):
     """ 
     For python 2 this is needed to convert a value to a bitwise string 
     in python 3 there is already a bin built in
     """
     s=''
     t={'0':'0000', '1':'0001', '2':'0010', '3':'0011',
        '4':'0100', '5':'0101', '6':'0110', '7':'0111',
        '8':'1000', '9':'1001', 'a':'1010', 'b':'1011',
        'c':'1100', 'd':'1101', 'e':'1110', 'f':'1111',
        }
     for c in hex(a)[2:]:
         s+=t[c]
     return s

def binrevers(hex):
   IntForm = int(hex, 16)
   BinForm = bin(IntForm)
   rBin = BinForm[::-1]
   Val = int(rBin, 2)
   return "%x" % Val

尝试交互式操作:

>>> binrevers("4BF8E")
'71fd2'
>>> 

如果你需要从 shell 中执行这个操作,那么可以通过在 .py 文件末尾添加以下内容来将其扩展为脚本:
if __name__ == "__main__":
    import sys
    for i in sys.argv[1:]:
       print i, binrevers(i)

嘿,谢谢。我对Python不是很了解,但我会尝试一下:)。它适用于任意数量的数字吗? - OgANgA
@OgANgA 上面的解决方案有两个不同之处:1)它会在非有效十六进制项上出错;2)它总是按字节对齐而不是半字节。 - Steve Barnes

0

我认为帮助可视化“比特反射”的一种方法是将其显示在所有256字节比特反射的网格中。

  • 008040C020A060E 0109050D030B070F0 088848C828A868E 8189858D838B878F8
  • 048444C424A464E 4149454D434B474F4 0C8C4CCC2CAC6CE C1C9C5CDC3CBC7CFC
  • 028242C222A262E 2129252D232B272F2 0A8A4ACA2AAA6AE A1A9A5ADA3ABA7AFA
  • 068646C626A666E 6169656D636B676F60E8E4ECE2EAE6EE E1E9E5EDE3EBE7EFE

.

  • 018141C121A161E 1119151D131B171F1098949C929A969E 9199959D939B979F9
  • 058545C525A565E 5159555D535B575F5 0D8D4DCD2DAD6DE D1D9D5DDD3DBD7DFD
  • 038343C323A363E 3139353D333B373F3 0B8B4BCB2BAB6BE B1B9B5BDB3BBB7BFB
  • 078747C727A767E 7179757D737B777F7 0F8F4FCF2FAF6FE F1F9F5FDF3FBF7FFF

对于每个字节,其对角线镜像的版本将是位反转的版本,如粗体示例所示:xF6x09

另一个特性是,当您将引用字符串切成两半并将它们堆叠在一起时,它们恰好相差1,而对角线关系也是同样的方式:
084C 2A6E :: 1st 1/2 - evens
195D 3B7F :: 2nd 1/2 -  odds

如果你想使用正则表达式从头开始重新创建参考字符串,而不是实际计算每个比特位,那么在你想要添加2个以上比特的每一层中使用这个...

00 & 10 & 01 & 11 &       # without the spaces

……这意味着,如果你想在没有访问原生的 按位异或 操作的情况下计算它们,四进制 是最有帮助的,因为只有中间对 1 | 2 交换,而外部对 0 | 3 保持不变。


0

使用以下算法:

  1. 将十六进制数转换为二进制等效形式。
  2. 执行按位非操作。
  3. 转换回十六进制。

1
我觉得_按位取反_没有起作用,我需要进行反转。你能请解释一下吗? - OgANgA

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