显示文件的十六进制数

21

我想编写一个Bash程序,可以读取文件,比如*.bin文件,并打印出其中所有的十六进制数,就像“hex”编辑器一样。我应该从哪里开始?


http://unix.stackexchange.com/questions/10826/shell-how-to-read-the-bytes-of-a-binary-file-and-print-as-hexadecimal - Ciro Santilli OurBigBook.com
5个回答

28
使用od命令:
od -t x1  filename

示例输出:

$ printf '0123456789abcdef0123456789abcdef\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f' | od -t x1
0000000 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66
*
0000040 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
0000060

od 是一个 Linux 程序还是一个 bash 函数?抱歉,我是一个真正的初学者。 - Nathan Campos
2
@Nathan Campos:你可以使用 which od 命令查看,如果你得到一个程序的名称,那么它就是一个外部程序(对于 od 命令来说,它很可能是这样的)。 - Greg Hewgill
4
这在Unix系统中非常常见,自unix诞生以来就一直存在。 - President James K. Polk
@GregHewgill 这是错的。从我的Ubuntu机器上看一下。~ $ type [
[ 是一个Shell内置命令
~ $ which [
/usr/bin/[
- GKFX
1
@NathanCampos 更重要的是它是POSIX:http://pubs.opengroup.org/onlinepubs/9699919799/utilities/od.html :-) - Ciro Santilli OurBigBook.com

26
编辑:添加了“bytestream”功能。如果脚本名称包含单词“stream”(例如,它是一个符号链接,如ln -s bash-hexdump bash-hexdump-stream,并作为./bash-hexdump-stream运行),它将输出表示文件内容的连续十六进制字符流。否则,它的输出将类似于hexdump -C
由于Bash不擅长处理二进制数据,因此需要使用一些技巧。
#!/bin/bash
# bash-hexdump
# by Dennis Williamson - 2010-01-04
# in response to https://dev59.com/YnI-5IYBdhLWcg3wI0p9
# usage: bash-hexdump file

if [[ -z "$1" ]]
then
    exec 3<&0                           # read stdin
    [[ -p /dev/stdin ]] || tty="yes"    # no pipe
else
    exec 3<"$1"            # read file
fi

# if the script name contains "stream" then output will be continuous hex digits
# like hexdump -ve '1/1 "%.2x"'
[[ $0 =~ stream ]] && nostream=false || nostream=true

saveIFS="$IFS"
IFS=""                     # disables interpretation of \t, \n and space
saveLANG="$LANG"
LANG=C                     # allows characters > 0x7F
bytecount=0
valcount=0
$nostream && printf "%08x  " $bytecount
while read -s -u 3 -d '' -r -n 1 char    # -d '' allows newlines, -r allows \
do
    ((bytecount++))
    printf -v val "%02x" "'$char"    # see below for the ' trick
    [[ "$tty" == "yes" && "$val" == "04" ]] && break    # exit on ^D
    echo -n "$val"
    $nostream && echo -n " "
    ((valcount++))
    if [[ "$val" < 20 || "$val" > 7e ]]
    then
        string+="."                  # show unprintable characters as a dot
    else
        string+=$char
    fi
    if $nostream && (( bytecount % 8 == 0 ))      # add a space down the middle
    then
        echo -n " "
    fi
    if (( bytecount % 16 == 0 ))   # print 16 values per line
    then
        $nostream && echo "|$string|"
        string=''
        valcount=0
        $nostream && printf "%08x  " $bytecount
    fi
done

if [[ "$string" != "" ]]            # if the last line wasn't full, pad it out
then
    length=${#string}
    if (( length > 7 ))
    then
        ((length--))
    fi
    (( length += (16 - valcount) * 3 + 4))
    $nostream && printf "%${length}s\n" "|$string|"
    $nostream && printf "%08x  " $bytecount
fi
$nostream && echo

LANG="$saveLANG";
IFS="$saveIFS"

撇号技巧在这里文档中有记录。相关部分如下:

如果前导字符是单引号或双引号,则值应为紧随其后的字符在底层代码集中的数值。

以下是脚本的一些输出,显示了我的/bin/bash的前几行以及更多内容:
00000000  7f 45 4c 46 01 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010  02 00 03 00 01 00 00 00  e0 1e 06 08 34 00 00 00  |............4...|
00000020  c4 57 0d 00 00 00 00 00  34 00 20 00 09 00 28 00  |.W......4. ...(.|
00000030  1d 00 1c 00 06 00 00 00  34 00 00 00 34 80 04 08  |........4...4...|
. . .
00000150  01 00 00 00 2f 6c 69 62  2f 6c 64 2d 6c 69 6e 75  |..../lib/ld-linu|
00000160  78 2e 73 6f 2e 32 00 00  04 00 00 00 10 00 00 00  |x.so.2..........|
00000170  01 00 00 00 47 4e 55 00  00 00 00 00 02 00 00 00  |....GNU.........|

1
顺便提一下,此脚本的输出格式与 hexdump -Chd 相同。 - Dennis Williamson
2
很高兴看到有人用Bash做一些不寻常甚至是二进制的事情,这段代码非常有趣! - ajaaskel
@nkvnkv:请仔细阅读问题:“我想构建一个bash程序...”此外,请注意我的答案已被提问者接受,并阅读附加在我的答案下的评论。感谢您的负评。 - Dennis Williamson

3
您可以使用od命令,例如"od -x file"。为什么要重复发明轮子呢?

1

如果您有hexdump,也可以使用它

hexdump -x /usr/bin/binaryfile

0
获取没有任何格式的原始十六进制字节字符串
当您想要转换数据而不是手动查看时,这个表单也可以很有用。
od -An -v -tx1 | tr -d ' \n'

例子:

printf '0123456789abcdef0123456789abcdef\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f' | od -An -v -tx1 | tr -d ' \n'

输出:

3031323334353637383961626364656630313233343536373839616263646566000102030405060708090a0b0c0d0e0f

所以没有空格或换行符,只有十六进制。

在Ubuntu 23.04上进行了测试。

相关链接: 如何在bash中创建一个只包含十六进制字符而没有空格的文件的十六进制转储?


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