Ответ 1
Вы можете использовать эхо, чтобы испускать определенные байты, используя шестнадцатеричный или восьмеричный. Например:
echo -n -e \\x30
будет печатать ascii 0 (0x30)
(- n удалить конечную новую строку)
У меня есть файл с двоичными данными, и мне нужно заменить несколько байтов в определенной позиции. Я придумал следующее, чтобы направить 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 должен запускаться как можно больше систем (я не знаю, будет ли у целевой системы питон или что-то еще установлено).
Как сообщить команде преобразовать вход в двоичный файл (возможно, из шестнадцатеричного)?
Вы можете использовать эхо, чтобы испускать определенные байты, используя шестнадцатеричный или восьмеричный. Например:
echo -n -e \\x30
будет печатать ascii 0 (0x30)
(- n удалить конечную новую строку)
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
xxd
- лучший способ. xxd -r infile outfile
примет значение ascii hex-value в infile для исправления outfile, и вы можете указать конкретную позицию в infile следующим образом: 1FE:55AA
Работали как удовольствие. Я использовал следующий код, чтобы заменить 4 байта на байт 24 в маленьком конце с двумя целыми числами (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' "$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 ; }
Вы можете использовать конвейер или перенаправление, чтобы поймать результат.
С 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"
}
В моем случае мне нужно было перейти от десятичного числового аргумента к фактическому 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