18

我有一个包含二进制数据的文件,我需要在某个位置替换几个字节。我想出了以下方法来将 bash 指向偏移量并告诉我它找到了我想要的位置:

dd bs=1 if=file iseek=24 conv=block cbs=2 | hexdump

现在,使用“文件”作为输出:

echo anInteger | dd bs=1 of=hextest.txt oseek=24 conv=block cbs=2

这似乎工作得很好,我可以查看在十六进制编辑器中所做的更改。问题是,“anInteger”将被写为该整数的 ASCII 表示(这是有道理的),但我需要编写二进制表示。

我想为此使用 bash,并且脚本应该在尽可能多的系统上运行(我不知道目标系统是否会安装 python 或其他任何东西)。

如何告诉命令将输入​​转换为二进制(可能来自十六进制)?

4

9 回答 9

16

printf比 更便携echo。此函数采用十进制整数并输出具有该值的字节:

echobyte () {
    if (( $1 >= 0 && $1 <= 255 ))
    then
        printf "\\x$(printf "%x" $1)"
    else
        printf "Invalid value\n" >&2
        return 1
    fi
}

$ echobyte 97
a
$ for i in {0..15}; do echobyte $i; done | hd
00000000  00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f  |................|
00000010
于 2010-04-30T20:10:55.417 回答
13

您可以使用 echo 使用十六进制或八进制发出特定字节。例如:

echo -n -e \\x30 

将打印 ascii 0 (0x30)

(-n 删除尾随换行符)

于 2010-04-30T18:32:06.553 回答
8

xxd是更好的方法。xxd -r infile outfile将 infile 中的 ascii hex-value 修补 outfile,您可以通过以下方式指定 infile 中的特定位置:1FE:55AA

于 2011-11-20T03:06:07.740 回答
4

工作就像一种享受。我使用以下代码用两个整数(1032 和 1920)替换小端序中字节 24 处的 4 个字节。该代码不会截断文件。

echo -e \\x08\\x04\\x80\\x07 | dd of=<file> obs=1 oseek=24 conv=block,notrunc cbs=4

再次感谢。

于 2010-04-30T20:16:39.043 回答
4

我有一个功能来做到这一点:

# number representation from 0 to 255 (one char long)
function chr() { printf "\\$(printf '%03o' "$1")" ; return 0 ; }
# from 0 to 65535 (two char long)
function word_litleendian() { chr $(($1 / 256)) ; chr $(($1 % 256)) ; return 0 ; }
function word_bigendian() { chr $(($1 % 256)) ; chr $(($1 / 256)) ; return 0 ; }
# from 0 to 4294967295 (four char long)
function dword_litleendian() { word_lilteendian $(($1 / 65536)) ; word_litleendian $(($1 % 65536)) ; return 0 ; }
function dword_bigendian() { word_bigendian $(($1 / 65536)) ; word_bigendian $(($1 % 65536)) ; return 0 ; }

您可以使用管道或重定向来捕获结果。

于 2015-07-21T19:23:07.120 回答
1

如果您愿意依赖 bc(这很常见)

echo -e "ibase=16\n obase=2 \n A1" | bc -q

可能有帮助。

于 2010-04-30T18:29:09.023 回答
1

对于 bash,“printf”具有“-v”选项,并且所有 shell 都有逻辑运算符。

所以这里是 bash 中更简单的形式:

int2bin() {
  local i=$1
  local f
  printf -v f '\\x%02x\\x%02x\\x%02x\\x%02x' $((i&255)) $((i >> 8 & 255)) $((i >> 16 & 255)) $((i >> 24 & 255))
  printf "$f"
}
于 2017-02-13T14:57:09.063 回答
0

您可以将所需的输入放入文件中并使用“if =”选项 dd 以准确插入所需的输入。

于 2010-04-30T18:29:38.457 回答
0

在我的例子中,我需要从一个十进制数字参数到实际的无符号 16 位大端值。这可能不是最有效的方法,但它有效:

# $1 is whatever number (0 to 65535) the caller specifies
DECVAL=$1
HEXSTR=`printf "%04x" "$DECVAL"`
BYTEONE=`echo -n "$HEXSTR" | cut -c 1-2`
BYTETWO=`echo -n "$HEXSTR" | cut -c 3-4`
echo -ne "\x$BYTEONE\x$BYTETWO" | dd of="$FILENAME" bs=1 seek=$((0xdeadbeef)) conv=notrunc
于 2017-08-18T19:24:10.620 回答