2010-04-30 8 views
13

Tengo un archivo con datos binarios y necesito reemplazar unos pocos bytes en una posición determinada. Yo he llegado con el siguiente golpe para dirigir a la compensación y me muestran que ha encontrado el lugar que quiero:usando bash: escribir la representación de bits del entero en el archivo

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

Ahora, para utilizar "archivo" como la salida:

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

Esto parece funcionar bien, puedo revisar los cambios realizados en un editor hexadecimal. El problema es que "anInteger" se escribirá como la representación ASCII de ese entero (lo cual tiene sentido) pero necesito escribir la representación binaria.

Quiero usar bash para esto y la secuencia de comandos debe ejecutarse en tantos sistemas como sea posible (no sé si el sistema de destino tendrá python o lo que sea).

¿Cómo le digo al comando que convierta la entrada en binario (posiblemente desde un hex)?

+0

Es posible que desee utilizar xdelta para esto, es bastante común que pueda ser "universal" para usted. – MikeyB

+0

No estoy seguro de lo que quiere decir con "xdelta". No hay tal comando en mi caparazón ... –

Respuesta

10

Puede usar echo para emitir bytes específicos usando hexadecimal u octal. Por ejemplo:

echo -n -e \\x30 

imprimirá ASCII 0 (0x30)

(-n eliminar salto de línea final)

+0

Esto parece funcionar. Trataré de resolverlo y publicar mis resultados. –

+3

echo es inquietantemente no portátil: para el ejemplo anterior, algunas implementaciones simplemente imprimirán '-e \ x30', que no es lo que quieres en absoluto. –

+0

Extraño, no lo hubiera pensado así. Por suerte, el script ya se está ejecutando sin problemas. –

0

Si estás dispuesto a confiar en BC (que es bastante común)

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

podría ayudar.

+0

Lo probé. Su código devolverá un binario que se escribirá en el archivo como la representación ASCII de ese binario. Bien pensado, gracias. –

0

Puede poner la entrada deseada en un archivo y usar la opción "if =" para dd para insertar exactamente la entrada que desee.

+0

Pensé en eso, pero no quiero usar un archivo adicional para 4 bytes. –

13

printf es más portátil que echo. Esta función toma un entero decimal y emite un byte con ese valor:

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

¡Dulce! Pero como puede ver en mi respuesta a continuación, eso probablemente sería excesivo. Aún así, es bueno saberlo. –

+0

Si conoce el número entero con anticipación, puede simplificarlo un poco, p. 'printf" \ x30 "' –

+0

@Gordon: Eso es cierto, vea la [respuesta de OP] (http://stackoverflow.com/questions/2746707/using-bash-write-bit-representation-of-integer-to-file/ 2747396 # 2747396). Sin embargo, el propósito de esta función es la versatilidad. –

4

Funcionó como una delicia. Usé el siguiente código para reemplazar 4 bytes en el byte 24 en little endian con dos enteros (1032 y 1920). El código no trunca el archivo.

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

Gracias de nuevo.

5

xxd es la mejor manera. xxd -r infile outfile se llevará a ascii valor hexadecimal en el archivo de entrada para reparar archivo de salida, y puede especificar la posición específica en el archivo de entrada por esto: 1FE:55AA

0

Tengo una función para hacer esto:

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

Puede utilizar tuberías o redirección para capturar el resultado.

0

Con bash, "printf" tiene la opción "-v" y todas las shell tienen operadores lógicos.

Así que aquí es la forma más simple en 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" 
} 
0

En mi caso, tenía que pasar de un argumento numérico decimal a la gran valor real sin signo de 16 bits endian. Probablemente esta no sea la forma más eficiente, pero funciona:

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