【问题标题】:How to convert hex to ASCII characters in the Linux shell?如何在 Linux shell 中将十六进制转换为 ASCII 字符?
【发布时间】:2009-10-22 02:52:50
【问题描述】:

假设我有一个字符串5a

这是 ASCII 字母 Z 的十六进制表示。

我需要知道一个 Linux shell 命令,它将接受一个十六进制字符串并输出该字符串所代表的 ASCII 字符。

如果我这样做:

echo 5a | command_im_looking_for

我会看到一封孤独的信Z

Z

【问题讨论】:

    标签: linux bash shell encoding scripting


    【解决方案1】:

    我以前用 xxd 来做这个

    echo -n 5a | xxd -r -p
    

    但后来我意识到在 Debian/Ubuntu 中,xxd 是 vim-common 的一部分,因此可能不会出现在最小系统中。为了避免 perl(恕我直言,这也不是最小系统的一部分),我最终使用了 sed、xargs 和 printf,如下所示:

    echo -n 5a | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf
    

    大多数情况下,我只想转换几个字节,这样的任务没问题。该解决方案相对于 ghostdog74 解决方案的优势在于,它可以自动转换任意长度的十六进制字符串。使用 xargs 是因为 printf 不从标准输入读取。

    【讨论】:

    • 该死的,我知道这是 3 年后的原始答案,但我不知道 xxd 存在。对于我现在遇到的问题,我一直需要它......来自调试器的字节字符串的持续十六进制转储。是的,@Vouze 评论毫无意义。
    • 我更喜欢使用"xxd -r -p <<< 5a",而不是"echo -n 5a | xxd -r -p"优点: (1) 输入的字符更少(由于 3 次重复,输入速度也更快); (2) 只运行 一个 命令(保存 echo),而不是 两个 => 更快的执行。
    • @KurtPfeifle sh: 1: Syntax error: redirection unexpected 缺点:不是 POSIX
    • @josch:对不起,我应该提到它需要 Bash 才能工作。它是 Bash 中的 here string(类似于 here document 的概念)。
    • xxd -r 在busybox中不可用,但第二个很好。谢谢
    【解决方案2】:
    echo -n 5a | perl -pe 's/([0-9a-f]{2})/chr hex $1/gie'
    

    请注意,这不会跳过非十六进制字符。如果您只想要十六进制(原始字符串中没有空格等):

    echo 5a | perl -ne 's/([0-9a-f]{2})/print chr hex $1/gie'
    

    另外,zshbashecho 中原生支持此功能:

    echo -e '\x5a'
    

    【讨论】:

    • 你可能需要在正则表达式后面加一个“i”。
    • 或者把a-fA-F放到字符类中。
    • 我通常不是 perl 的粉丝,但这是它擅长的东西。但是,如果您要转换大量数据,最好编写一个简短的 C 程序来执行此操作。
    • 更容易使用perl -lne 'print pack "H*", $_'
    • echo -ne '\x5a' 是必要的,例如:如果没有 -n 开关来回显,将在 Z 之后输出一个新行 ('\x0a')。
    【解决方案3】:

    你可以只通过 echo 而不用其他东西。不要忘记添加“-n”,否则会自动换行:

    echo -n -e "\x5a"
    

    【讨论】:

    • 不回答上面提出的问题,但回答了我在谷歌将我发送到此处时正在搜索的问题:-)(顺便说一句。将输出发送到 | hexdump -C 有助于识别不需要的换行符等.)
    • 不错,但是需要 BAsh
    • 这要求在每个十六进制对之前插入\x。示例是 5a,但问题是关于将十六进制字符串转换为多个 ASCII 字符。
    【解决方案4】:

    猛击单行

    echo -n "5a" | while read -N2 code; do printf "\x$code"; done
    

    【讨论】:

    • 这似乎不适用于多字节消息...当我运行echo -n "0102abcd" | while read -n 2 code; do printf "\x$code"; done | hexdump 时产生0201 cdab
    • @John Steel 似乎 hexdump 默认将数据显示为十六进制的数字单词。试试这个echo -n "0102abcd" | while read -n 2 code; do printf "\x$code"; done | hexdump -e '/1 "%02x"'
    【解决方案5】:

    根据你得到“5a”的位置,你可以将 \x 附加到它并传递给 printf

    $ a=5a
    $ a="\x${a}"
    $ printf "$a"
    Z
    

    【讨论】:

    • 第二行和第三行可以合二为一:printf "\x${a}"
    【解决方案6】:

    一些可处理任意字节数的 python3 单行代码。

    解码十六进制(使用strip,以便在标准输入上有一个换行符):

    $ echo 666f6f0a | python3 -c "import sys, binascii; sys.stdout.buffer.write(binascii.unhexlify(input().strip()))"
    foo
    

    十六进制编码:

    $ echo foo | python3 -c "import sys, binascii; print(binascii.hexlify(sys.stdin.buffer.read()).decode())"
    666f6f0a
    

    【讨论】:

    • 解码十六进制时只需使用打印,您可以看到 ctrl 字符、空字符等。例如'回声 666f6f0a62617200 | python3 -c "import sys, binascii; print(binascii.unhexlify(input()))"' 输出:'b'foo\nbar\x00''
    【解决方案7】:
    echo 5a | python -c "import sys; print chr(int(sys.stdin.read(),base=16))"
    

    【讨论】:

    • print 更改为sys.stdout.write 以防止出现额外的换行符。
    • OverflowError: Python int too large to convert to C long
    【解决方案8】:

    这是一个纯 bash 脚本(因为 printf 是一个 bash 内置):

    #warning : spaces do matter
    die(){ echo "$@" >&2;exit 1;}
    
    p=48656c6c6f0a
    
    test $((${#p} & 1)) == 0 || die "length is odd"
    p2=''; for ((i=0; i<${#p}; i+=2));do p2=$p2\\x${p:$i:2};done
    printf "$p2"
    

    如果 bash 已经在运行,这应该比任何其他启动新进程的解决方案都要快。

    【讨论】:

    • 略短:for ((i=0; i&lt;${#p}; i+=2));do p2+=\\x${p:$i:2};done
    【解决方案9】:

    dc 可以在数字基数之间进行转换:

    $ echo 5a | (echo 16i; tr 'a-z' 'A-Z'; echo P) | dc
    Z$
    

    【讨论】:

      【解决方案10】:

      根据@Randal comment,可以使用perl,例如

      $ printf 5a5a5a5a | perl -lne 'print pack "H*", $_'
      ZZZZ
      

      还有其他方式:

      $ printf ZZZZ | perl -lne 'print unpack "H*", $_'
      5a5a5a5a
      

      另一个文件示例:

      $ printf 5a5a5a5a | perl -lne 'print pack "H*", $_' > file.bin
      $ perl -lne 'print unpack "H*", $_' < file.bin
      5a5a5a5a
      

      【讨论】:

        【解决方案11】:

        有一个简单的shell命令“ascii”,

        如果你使用 Ubuntu,只需

        sudo apt install ascii
        

        然后:

        ascii 0x5a
        

        将输出:

        ASCII 5/10 is decimal 090, hex 5a, octal 132, bits 01011010: prints as `Z'
        Official name: Majuscule Z
        Other names: Capital Z, Uppercase Z
        

        【讨论】:

          【解决方案12】:

          您可以将此命令(python 脚本)用于更大的输入:

          echo 58595a | python -c "import sys; import binascii; print(binascii.unhexlify(sys.stdin.read().strip()).decode())"
          

          结果将是:

          XYZ
          

          为了更简单,定义一个别名:

          alias hexdecoder='python -c "import sys; import binascii; print(binascii.unhexlify(sys.stdin.read().strip()).decode())"'
          
          echo 58595a | hexdecoder
          

          【讨论】:

            【解决方案13】:

            GNU awk 4.1

            awk -niord '$0=chr("0x"RT)' RS=.. ORS=
            

            请注意,如果您对此进行回显,它将产生一个额外的空字节

            $ echo 595a | awk -niord '$0=chr("0x"RT)' RS=.. ORS= | od -tx1c
            0000000  59  5a  00
                      Y   Z  \0
            

            改为使用 printf

            $ printf 595a | awk -niord '$0=chr("0x"RT)' RS=.. ORS= | od -tx1c
            0000000  59  5a
                      Y   Z
            

            另请注意,GNU awk 默认生成 UTF-8

            $ printf a1 | awk -niord '$0=chr("0x"RT)' RS=.. ORS= | od -tx1
            0000000 c2 a1
            

            如果您正在处理 ASCII 以外的字符,并且您将 Base64 编码结果字符串,您可以使用 -b 禁用 UTF-8

            echo 5a | sha256sum | awk -bniord 'RT~/\w/,$0=chr("0x"RT)' RS=.. ORS=
            

            【讨论】:

              【解决方案14】:

              与我在这里的回答类似:Linux shell scripting: hex number to binary string

              您可以使用类似这样的相同工具来完成此操作(使用 ascii 可打印字符而不是 5a):

              echo -n 616263 | cryptocli dd -decoders hex
              

              会产生以下结果:

              abcd
              

              【讨论】:

                猜你喜欢
                • 2014-11-16
                • 2011-11-21
                • 2017-10-26
                • 1970-01-01
                • 1970-01-01
                • 2016-09-27
                • 1970-01-01
                • 2011-06-14
                相关资源
                最近更新 更多