2010-04-30 5 views
13

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

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

+0

Возможно, вы захотите использовать xdelta для этого - достаточно распространено, что оно может быть «универсальным» для вас. – MikeyB

+0

Не уверен, что вы подразумеваете под "xdelta". В моей оболочке нет такой команды ... –

ответ

10

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

echo -n -e \\x30 

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

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

+0

Это похоже на работу. Я постараюсь понять это и опубликовать свои результаты. –

+3

Эхо возмутительно не переносимо - для примера выше некоторые реализации будут просто печатать '-e \ x30', что совсем не то, что вы хотите. –

+0

Странно, не подумал бы. К счастью, скрипт уже работает без проблем. –

0

Если вы готовы полагаться на Ьс (который является довольно распространенным)

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

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

+0

Я попробовал. Ваш код вернет двоичный файл, который будет записан в файл как представление ASCII этого двоичного файла. Приятно подумать, спасибо. –

0

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

+0

Я думал об этом, но я не хочу использовать дополнительный файл для 4 байтов. –

13

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 
+0

Сладкий! Но, как вы можете видеть в моем ответе ниже, это, вероятно, будет излишним. Тем не менее, приятно знать. –

+0

Если вы знаете число (ы) заранее, вы можете упростить это довольно немного, например. 'printf" \ x30 "' –

+0

@Gordon: Это верно, см. ответ [OP] (http://stackoverflow.com/questions/2746707/using-bash-write-bit-representation-of-integer-to-file/ 2747396 # 2747396). Однако вся цель этой функции - универсальность. –

4

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

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

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

5

xxd - лучший способ. xxd -r infile outfile будет принимать ASCii шестнадцатеричное значение в INFILE залатать выходной_файл, и вы можете указать конкретную позицию в INFILE на это: 1FE:55AA

0

У меня есть функция, чтобы сделать это:

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

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

0

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

Так вот проще форма в Баш:

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" 
} 
0

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

# $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 

 Смежные вопросы

  • Нет связанных вопросов^_^