如何在 Bash 中将二进制值而不是 ASCII 值写入文件

DEK*_*KER 7 linux bash echo devices hex

我正在处理一个嵌入式系统,它有一些可以通过文件描述符访问的内存(我不知道我在说什么,所以如果我错了,请纠正我)。

该内存为 32 kB,我想用 0x00 到 0xFFFFFFFF 填充它。我知道文本文件是这样的:

exec {fh} >> ./eeprom;
for i in {0..32767}; do echo $i >& $fh; done; $fh>&-;
Run Code Online (Sandbox Code Playgroud)

这将写入 ASCII 字符 0 到 977。

如果我这样做,hexdump eeprop | head我会得到:

0000000 0a30 0a31 0a32 0a33 0a34 0a35 0a36 0a37
0000010 0a38 0a39 3031 310a 0a31 3231 310a 0a33
0000020 3431 310a 0a35 3631 310a 0a37 3831 310a
0000030 0a39 3032 320a 0a31 3232 320a 0a33 3432
0000040 320a 0a35 3632 320a 0a37 3832 320a 0a39
0000050 3033 330a 0a31 3233 330a 0a33 3433 330a
0000060 0a35 3633 330a 0a37 3833 330a 0a39 3034
0000070 340a 0a31 3234 340a 0a33 3434 340a 0a35
0000080 3634 340a 0a37 3834 340a 0a39 3035 350a
0000090 0a31 3235 350a 0a33 3435 350a 0a35 3635
Run Code Online (Sandbox Code Playgroud)

如何用它的uint32而非 ASCII 表示形式填充每个地址?

Sté*_*las 10

perl -e 'print pack "L*", 0..0x7fff' > file
Run Code Online (Sandbox Code Playgroud)

将以本地系统的字节顺序写入它们。

使用:

perl -e 'print pack "L>*", 0..0x7fff'
perl -e 'print pack "L<*", 0..0x7fff'
Run Code Online (Sandbox Code Playgroud)

无论本地系统的本机字节序如何,分别强制使用大端字节序或小端字节序。

perldoc -f pack详情请参阅。

特别是使用 bash 内置函数,您可以使用以下命令写入任意字节值:

printf '\123' # 123 in octal
printf '\xff' # ff in hexadecimal
Run Code Online (Sandbox Code Playgroud)

因此,您可以通过手动写入 uint32 数字的每个字节来完成此操作,如下所示:

for ((i = 0; i <= 32767; i++)); do
  printf -v format '\\x%x' \
    "$((         i & 0xff ))" \
    "$(( (i >>  8) & 0xff ))" \
    "$(( (i >> 16) & 0xff ))" \
    "$(( (i >> 24) & 0xff ))"
  printf "$format"
done
Run Code Online (Sandbox Code Playgroud)

(此处为小端)。

无论如何,请注意 32767 是 0x7fff,而不是0xFFFFFFFF。uint32 数字 0 到 32767 占用 128KiB,而不是 32kb。0 到 0xFFFFFFFF 将占用 16GiB。

要将这些 16GiB 写入 中perl,您需要将代码更改为:

perl -e 'print pack "L", $_ for 0..0xffffffff'
Run Code Online (Sandbox Code Playgroud)

否则它会尝试(并且可能会失败)在内存中分配这 16GiB。在我的系统上,我发现perl写入输出的速度约为 30MiB/s,而bash写入的速度约为 250KiB/s(因此需要几个小时才能完成)。

要写入 32kb(32000 位、4000 字节、1000 个 uint32 数字)的 uint32 数字,您可以使用 0..999 范围。32KiB 为 0..8191。L或者您可以通过将(unsigned long) 替换为S(unsigned Short)将 0..16383 写为 uint16 数字。

  • @paulgarrett,这并不奇怪,shell 被设计用来运行命令(例如 perl 解释器),perl 是一种通用编程语言。 (4认同)
  • @DEKKER,`head -c 131072 &lt; /dev/zero 1&lt;&gt; file` 用 0 覆盖 `file` 的前 128KiB。另请参阅“fallocate -p”在文件中打孔。 (2认同)