Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

Вы можете использовать эхо, чтобы испускать определенные байты, используя шестнадцатеричный или восьмеричный. Например:

echo -n -e \\x30 

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

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

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

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

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

# 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 ; }

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

Ответ 8

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

Итак, вот более простая форма в 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"
}

Ответ 9

В моем случае мне нужно было перейти от десятичного числового аргумента к фактическому 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