¿Cómo extraigo un solo fragmento de bytes de un archivo?

81

En un escritorio Linux (RHEL4), quiero extraer un rango de bytes (generalmente menos de 1000) desde un archivo grande (> 1 Gig). Conozco el desplazamiento en el archivo y el tamaño del fragmento.

Puedo escribir código para hacer esto, pero ¿hay una solución de línea de comando?

Idealmente, algo como:

magicprogram --offset 102567 --size 253 < input.binary > output.binary
DanM
fuente

Respuestas:

121

Prueba dd:

dd skip=102567 count=253 if=input.binary of=output.binary bs=1
Thomas Padron-McCarthy
fuente
2
Opcionalmente, agregue status=nonepara suprimir la salida a stderr.
Kenorb
13
Aquí es ejemplo usando compensaciones hexagonales: dd if=in.bin bs=1 status=none skip=$((0x88)) count=$((0x80)) of=out.bin.
Kenorb
@kenorb: Creo que la sintaxis hexadecimal es parte de Bash, por lo que no necesariamente funciona con otros shells. Yo mismo uso tcsh (¡no me pegues!) Y tu ejemplo no funciona allí.
Thomas Padron-McCarthy
1
¿Existe una razón específica por la que usa bs = 1 y count = 253 y no al revés? ¿El tamaño de bloque más grande haría que el comando fuera más eficiente?
Rexford
1
@rexford: El número de omisión también se da en bloques y no es un múltiplo de 253. Y dado que el sistema operativo hace su propio almacenamiento en búfer cuando lee de un archivo normal en un sistema de archivos, en este caso la eficiencia no será tan básica como al leer desde un dispositivo.
Thomas Padron-McCarthy
55

Esta es una pregunta antigua, pero me gustaría agregar otra versión del ddcomando que sea más adecuada para grandes cantidades de bytes:

dd if=input.binary of=output.binary skip=$offset count=$bytes iflag=skip_bytes,count_bytes 

donde $offsety $bytesson números en unidades de bytes.

La diferencia con la respuesta aceptada de Thomas es que bs=1no aparece aquí. bs=1produce que el tamaño del bloque de entrada y salida sea de 1 byte, lo que lo hace terriblemente lento cuando la cantidad de bytes a extraer es grande.

Gatillo crono
fuente
4
De hecho, esto es mucho más rápido que mi respuesta.
Thomas Padron-McCarthy
1
No funciona en Mac: iflages un operando desconocido y sin él obtienes un bloque completo.
Timmmm
1
@Timmmm GNU ddse puede utilizar como iflagsoporte ( brew install coreutils). Nota: por defecto, las utilidades se instalan con un gprefijo (por ejemplo, en gddlugar de dd)
Shakil
el truco perfecto para acelerar, iba a dividir un archivo de 48 GB y esto me salvó la vida
Ali Nadalizadeh
11

head -c + tail -c

No estoy seguro de cómo se compara con la ddeficiencia, pero es divertido:

printf "123456789" | tail -c+2 | head -c3

elige 3 bytes, comenzando en el segundo:

234

Véase también: https://stackoverflow.com/a/1272995/895245

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
@ elvis.dukaj sí, no debería ser diferente. Pruébelo con printf '\x01\x02' > fy hd.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
Mucho más rápido que dd con bs = 1, ¡gracias! Tenga en cuenta que tail cuenta bytes desde 1, no desde 0. Además, tail sale con el código de error 1 cuando su salida se cierra prematuramente por head. Asegúrese de ignorar ese error cuando utilice "set -e".
proski
2

El comando dd puede hacer todo esto. Observe los parámetros de búsqueda y / o omisión como parte de la llamada.

Joe
fuente
2

Aun más rápido

dd bs=<req len> count=1 skip=<req offset> if=input.binary of=output.binary 
Albert Burbea
fuente
2
El problema aquí es que skipestá en unidades de bs.
Arkku
sin embargo, esta debería ser la respuesta más votada, la de arriba con bs = 1 es muy lenta: D
Tchakabam
es un detalle para el ejecutor, y aún mejor que el anterior, es cierto que necesitaría volver a calcular como: req_offset=$(bc <<< "$offset/$bs")y asegurarse de que resulte un valor redondo.
Tchakabam