如何将 8 个字节“读取/解释”为无符号整数(Little Endian)?
也许为此有一个 Bash-fu 魔法转换?
更新:
在我的问题的解释中,似乎有些事情发生了交叉。这是我正在尝试做的一个更广泛的例子。
我想读取文件的第一个(也是最后一个)64k。每个 8 字节字将被解释为 64 位小端无符号整数。这些整数将用于唯一标识文件的散列计算。所以有很多计算要进行, ? 速度是首选,但不是关键。(我为什么要这样做?因为smplayer散列其播放的媒体 .ini 文件的名称,我想访问和修改这些文件,所以我在 Bash 中模仿了 smplayer 的 C++ 代码。)
迎合接受管道输入的解决方案将是最佳的,并且可能是必不可少的,因为 Bash 变量无法处理 \x00..
我意识到像这样的东西可能更适合 Python、Perl 和 C/C++ 之类的东西,但我不知道 Python 和 Perl,虽然我可以用 C++ 来做,但我已经好几年没用了它,我正试图专注于 Bash。
简短的 Perl 和 Python 片段很好。Bash 是首选(但不以牺牲速度为代价)。
Bash 完全是错误的工具。贝壳擅长将点点滴滴粘在一起;文本处理和算术是在旁边提供的,数据处理根本不在他们的范围内。
我会选择 Python 而不是 Perl,因为 Python 马上就有了 bignums。使用struct.unpack解压数据。
#!/usr/bin/env python
import os, struct, sys
fmt = "<" + "Q" * 8192
header_bytes = sys.stdin.read(65536)
header_ints = list(struct.unpack(fmt, header_bytes))
sys.stdin.seek(-65536, 2)
footer_bytes = sys.stdin.read(65536)
footer_ints = list(struct.unpack(fmt, header_bytes))
# your calculations here
Run Code Online (Sandbox Code Playgroud)
这是我对原始问题的回答。修改后的问题与原问题没有太大关系,原问题是将一个 8 字节序列转换为它以小端顺序表示的 64 位整数。
我认为 bash 没有任何内置功能。以下代码段设置a为一个字符串,该字符串是与指定字符串中按大端顺序对应的字节数的十六进制表示形式。
a=0x$(printf "%s" "$string" |
od -t x1 -An |
tr -dc '[:alnum:]')
Run Code Online (Sandbox Code Playgroud)
对于小端顺序,反转原始字符串中字节的顺序。在 bash 中,对于已知长度的字符串,您可以执行
a=0x$(printf "%s" "${string:7:1}${string:6:1}${string:5:1}${string:4:1}${string:3:1}${string:2:1}${string:1:1}${string:0:1}" |
od -t x1 -An |
tr -dc '[:alnum:]')
Run Code Online (Sandbox Code Playgroud)
如果您od支持 8 字节类型,您还可以获得平台的首选字节序。
a=0x$(printf "%s" "$string" |
od -t x8 -An |
tr -dc '[:alnum:]')
Run Code Online (Sandbox Code Playgroud)
您是否可以进行算术运算$a取决于您的 bash 是否支持 8 字节算术。即使是这样,它也会将其视为有符号值。
或者,使用 Perl:
a=0x$(perl -e 'print unpack "Q<", $ARGV[0]' "$string")
Run Code Online (Sandbox Code Playgroud)
如果您的 perl 是在没有 64 位整数支持的情况下编译的,您需要将字节分解。
a=0x$(perl -e 'printf "%x%08x\n", reverse unpack "L<L<", $ARGV[0]' "$string")
Run Code Online (Sandbox Code Playgroud)
(替换<用>的大端或删除它,以获得平台字节顺序。)