использование bash: запись битового представления integer в файл

у меня есть файл с двоичными данными, и мне нужно заменить несколько байтов в определенной позиции. Я придумал следующее, чтобы направить 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

Это, кажется, работает просто отлично, я могу просмотреть изменения, сделанные в Редакторе hex. Проблема в том, что "anInteger" будет записан как ASCII-представление этого целого числа (что имеет смысл), но мне нужно написать двоичное представление.

Я хочу использовать bash для этого, и скрипт должен работать на как можно большем количестве систем (я не знаю, будет ли в целевой системе установлен python или что-то еще).

Как я могу сказать команде преобразовать вход в двоичный (возможно, из шестнадцатеричного)?

9 ответов


вы можете использовать echo для выделения определенных байтов с помощью шестнадцатеричного или восьмеричного. Например:

echo -n -e \x30 

будет печатать ascii 0 (0x30)

(- n удалить конечную новую строку)


printf является более портативным, чем echo. Эта функция принимает десятичное целое число и выводит байт с таким значением:

echobyte () {
    if ((  >= 0 &&  <= 255 ))
    then
        printf "\x$(printf "%x" )"
    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

xxd - Это лучший способ. xxd -r infile outfile примет шестнадцатеричное значение ascii в infile для исправления outfile, и вы можете указать конкретную позицию в infile следующим образом:1FE:55AA


работал как удовольствие. Я использовал следующий код для замены 4 байтов на байт 24 в little endian двумя целыми числами (1032 и 1920). Код не усекает файл.

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

еще раз спасибо.


Если вы готовы полагаться на bc (что довольно распространено)

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

может помочь.


вы можете поместить желаемый ввод в файл и использовать опцию" if= " для DD, чтобы вставить именно тот ввод, который вы хотите.


У меня есть функция для этого:

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

вы можете использовать трубопровод или перенаправление, чтобы поймать результат.


С bash, "printf" имеет опцию"- v", и вся оболочка имеет логические операторы.

Итак, вот более простая форма в bash:

int2bin() {
  local i=
  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"
}

в моем случае мне нужно было перейти от десятичного числового аргумента к фактическому 16-битному значению без знака. Это, вероятно, не самый эффективный способ, но он работает:

#  is whatever number (0 to 65535) the caller specifies
DECVAL=
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