¿Cuál es la forma POSIX de leer un número exacto de bytes desde un file?

Simplemente click este problema y aprenda mucho de la respuesta elegida: Cree datos aleatorios con dd y obtenga "advertencia de lectura parcial". ¿Los datos después de la advertencia ahora son realmente aleatorios?

Lamentablemente, la solución sugerida head -c no es portátil.

Para las personas que insisten en que dd es la respuesta, lea atentamente la respuesta vinculada que explica en gran detalle por qué dd no puede ser la respuesta. Además, por favor, tenga en count esto:

 $ dd bs=1000000 count=10 if=/dev/random of=random dd: warning: partial read (89 bytes); suggest iflag=fullblock 0+10 records in 0+10 records out 143 bytes (143 B) copied, 99.3918 s, 0.0 kB/s $ ls -l random ; du -kP random -rw-rw-r-- 1 me me 143 Apr 22 19:19 random 4 random $ pwd /tmp 

Desafortunadamente, para manipular el contenido de un file binary, dd es prácticamente la única herramienta en POSIX. Aunque la mayoría de las implementaciones modernas de herramientas de procesamiento de text ( cat , sed , awk , …) pueden manipular files binarys, POSIX no requiere esto: algunas implementaciones más antiguas se ahogan en bytes nulos, inputs no terminadas por una nueva línea o secuencias de bytes no válidos en la encoding de caracteres ambientales.

Es posible, pero difícil, usar dd forma segura. La razón por la que gasto mucha energía alejando a la gente de eso es que hay muchos consejos que promueven la dd en situaciones donde no es útil ni segura.

El problema con dd es su noción de bloques: asume que una llamada a read devuelve un bloque; si read devuelve less datos, obtienes un locking parcial, que arroja cosas como skip y count . Aquí hay un ejemplo que ilustra el problema, donde dd lee de un conducto que entrega datos de forma relativamente lenta:

 yes hello | while read line; do echo $line; done | dd ibs=4 count=1000 | wc -c 

En un Linux estándar de pantano (Debian jessie, Linux kernel 3.16, dd de GNU coreutils 8.23), obtengo un número muy variable de bytes, que van desde aproximadamente 3000 hasta casi 4000. Cambie el tamaño del bloque de input a un divisor de 6, y la salida es consistentemente de 4000 bytes como se esperaría ingenuamente: la input a dd llega en ráfagas de 6 bytes, y mientras un bloque no abarque múltiples ráfagas, dd lee un bloque completo.

Esto sugiere una solución: use un tamaño de bloque de input de 1 . No importa cómo se produzca la input, no hay forma de que dd lea un bloque parcial si el tamaño del bloque de input es 1. (Esto no es completamente obvio: dd podría leer un bloque de tamaño 0 si se ve interrumpido por una señal, pero si se interrumpe por una señal, la llamada al sistema de read devuelve -1. Una read retorna 0 solo es posible si el file se abre en modo no bloqueante, y en ese caso una read no debería considerarse realizada en absoluto. En el modo de locking, read only devuelve 0 al final del file.)

 dd ibs=1 count="$number_of_bytes" 

El problema con este enfoque es que puede ser lento (pero no sorprendentemente lento: solo aproximadamente 4 veces más lento que la head -c en mi reference rápida).

POSIX define otras herramientas que leen datos binarys y los convierten a un formatting de text: uuencode (salidas en formatting histórico de uuencode o en Base64), od (genera un volcado hexadecimal o octal). Ninguno de los dos es adecuado para la tarea en cuestión. uuencode puede ser deshecho por uudecode , pero contar bytes en la salida es incómodo porque el número de bytes por línea de salida no está estandarizado. Es posible get resultados bien definidos a partir de od , pero desafortunadamente no hay una herramienta POSIX para ir al revés (se puede hacer, pero solo a través de loops lentos en sh o awk, lo cual frustra el propósito aquí).

Parte del punto de usar dd es que el usuario puede elegir el tamaño de bloque que usa. Si dd falla para tamaños de bloques demasiado grandes, IMO es responsabilidad del usuario probar tamaños de bloques más pequeños. Podría pedir un TB de dd en un bloque, pero eso no significa que lo conseguiré.

Si quieres un número exacto de bytes, esto será tremendamente lento, pero debería funcionar:

 dd bs=1 count=1000000 

Si incluso un tamaño de bloque de 1 da como resultado lecturas parciales, …

    Intereting Posts