使用 bash 从二进制文件中提取单个字节到变量中

使用 bash 从二进制文件中提取单个字节到变量中

我需要制作一个相当简单的 bash 脚本,从二进制文件中一次提取一个字节,将其发送到串行端口,然后等待一个字节返回,然后再发送下一个字节。这对于 EEPROM 编程器来说非常有效,因为现成的解决方案无法工作。

我主要致力于将字节从文件中提取到变量中,除此之外我知道我可以将值回显到串行端口并使用 dd 读回它们。 (还有更好的方法吗?)

谢谢您的帮助!

答案1

使用ddor xxd(Vim 的一部分),例如从二进制文件中读取-l偏移量 100 ( ) 处的一个字节 ( ) 尝试:-s

xxd -p -l1 -s 100 file.bin

要使用十六进制偏移量,在 Bash 中您可以使用以下语法$((16#64)),例如:

echo $((16#$(xxd -p -l1 -s $((16#FC)) file.bin)))

它在偏移处读取字节FC并以十进制格式打印它。

或者使用dd,例如:

dd if=file.bin seek=$((16#FC)) bs=1 count=5 status=none

它将在十六进制偏移处转储 5 个字节的原始数据FC

然后你可以将它分配给变量,但是它当您的数据有 NULL 字节时将不起作用,因此您可以跳过它们 ( xxd -a),或者作为解决方法,您可以将它们存储为纯十六进制格式。

例如:

  1. 将偏移量 10 处的 10 个字节读入包含十六进制格式字节的变量:

    hex=$(xxd -p -l 10 -s 10 file.bin)
    
  2. 然后将它们写入文件或设备:

    xxd -r -p > out.bin <<<$hex
    

以下是 Bash 中的一些有用的函数:

set -e

# Read single decimal value at given offset from the file.
read_value() {
  file="$1"
  offset="$2"
  [ -n "$file" ]
  [ -n "$offset" ]
  echo $((16#$(xxd -p -l1 -s $offset "$file")))
}

# Read bytes in hex format at given offset from the file.
read_data() {
  file="$1"
  offset="$2"
  count="$3:-1"
  xxd -p -l $count -s $offset "$file"
}

使用示例:

read_value file.bin $((16#FC)) # Read 0xFC offset from file.bin.

答案2

我不确定我是否理解您所要求的总体情况,但我有几种您可能需要考虑的方法:

用于dd读取您的输入文件

执行3<输入文件
虽然是真的
    dd bs=1 count=1 <&3 > this_byte
    如果 ! [ -s this_byte ] # 如果大小为零,我们就完成了。
    然后
        休息
    代码使用这个字节文件
完毕

用于od消化您的输入文件

OD-BV输入文件|同时读取a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16
do # 跳过 $a0;这是地址。
    对于“$a1”“$a2”“$a3”“$a4”“$a5”“$a6”“$a7”“$a8”“$a9”“$a10”中的 byte_val \
                                “$a11” “$a12” “$a13” “$a14” “$a15” “$a16”
        如果[“$byte_val”=“”]
        然后
            休息
        代码使用$byte_val价值
        例如:echo -e "\0$byte_val\c"
    完毕
完毕

答案3

使用一个小型 C 程序或 Python 或 Perl 等脚本语言中的(几乎)一行代码可能更容易做到这一点。

Unix shell 是一个用户命令的解释器,(为了方便编写重复命令)具有基本的编程设施。它经常被(误)使用,因为 Bourne shell 的一个版本是保证它可以在任何 Unix 系统上使用,并不是因为它是一种特别好的(甚至是半途而废的)编程语言。

答案4

您可以使用perl

$ printf '%s%s%s' 'ăâé' | LC_ALL=C.UTF-8 perl -Mopen=locale -ne '
    BEGIN { $/ = \1 }
    printf "%s\n", $_;
'
ă
â
é

相关内容