如何在 Linux shell 中将十六进制转换为 ASCII 字符?

假设我有一个字符串 5a

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

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

因此,如果我这样做:

echo 5a | command_im_looking_for

我将看到一个单独的字母 Z:

Z
134638 次浏览
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'
echo 5a | python -c "import sys; print chr(int(sys.stdin.read(),base=16))"

取决于你从哪里得到的“5a”,你可以在它前面加上“ x”,然后把它传递给 printf:

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

我曾经用 谢谢做过这个:

echo -n 5a | xxd -r -p

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

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

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

你可以只用 echo做这件事,不用其他东西。不要忘记加上“-n”,否则你会自动得到一个换行符:

echo -n -e "\x5a"

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=

下面是一个纯 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 已经在运行,那么它应该比启动新进程的任何其他解决方案都要快。

狠狠地说一句俏皮话

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

Dc 可以在数字基础之间转换:

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

一些 Python 3一行程序可以处理任意数量的字节。

解码巫术

使用 strip,这样就可以在 stdin 上使用换行了。

$ 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

与我的答案相似: Linux shell 脚本: 十六进制数到二进制字符串

你可以用同样的工具做到这一点(使用 ascii 可打印字符而不是 5a) :

echo -n 616263 | cryptocli dd -decoders hex

会产生以下结果:

abcd

根据 @ 兰德尔评论,你可以使用 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

有一个简单的 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

您可以使用这个命令(python script)进行更大的输入:

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