GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cuándo es adecuado Dd para copiar datos? (o, ¿cuándo son parciales Read() y Write())?

Versión corta: ¿En qué circunstancias es dd seguro de usar para copiar datos, ¿seguro significa que no hay riesgo de corrupción debido a una lectura o escritura parcial?

Versión larga — preámbulo: dd se usa a menudo para copiar datos, especialmente desde o hacia un dispositivo (ejemplo). A veces se le atribuyen propiedades místicas de poder acceder a dispositivos a un nivel más bajo que otras herramientas (cuando en realidad es el archivo del dispositivo el que hace la magia), pero dd if=/dev/sda es lo mismo que cat /dev/sda . dd a veces se piensa que es más rápido, pero cat puede vencerlo en la práctica. No obstante, dd tiene propiedades únicas que lo hacen genuinamente útil a veces.

Problema: dd if=foo of=bar no es, de hecho, lo mismo que cat <foo >bar . En la mayoría de los unice¹, dd hace una sola llamada a read() . (Encuentro POSIX confuso en lo que constituye "leer un bloque de entrada" en dd .) Si read() devuelve un resultado parcial (que, según POSIX y otros documentos de referencia, está permitido a menos que la documentación de implementación indique lo contrario), se copia un bloque parcial. Exactamente el mismo problema existe para write() .

Observaciones :En la práctica, he encontrado que dd puede hacer frente a dispositivos de bloque y archivos normales, pero eso puede deberse a que no lo he ejercitado mucho. Cuando se trata de tuberías, no es difícil poner dd en falta; por ejemplo, prueba este código:

yes | dd of=out bs=1024k count=10

y verifique el tamaño del out archivo (es probable que tenga menos de 10 MB).

Pregunta :¿En qué circunstancias es dd seguro de usar para copiar datos? En otras palabras, qué condiciones en los tamaños de bloque, en la implementación, en los tipos de archivos, etc., pueden asegurar que dd copiará todos los datos?

(GNU dd tiene un fullblock bandera para decirle que llame a read() o write() en un bucle para transferir un bloque completo. Entonces dd iflag=fullblock siempre es seguro. Mi pregunta es sobre el caso en que no se utilizan estas banderas (que no existen en otras implementaciones).

¹
Revisé OpenBSD, GNU coreutils y BusyBox.

Respuesta aceptada:

De la especificación:

  • Si bs= expr se especifica el operando y no hay más conversiones que sync , noerror , o notrunc se solicitan, los datos devueltos de cada bloque de entrada se escribirán como un bloque de salida separado; si read() devuelve menos de un bloque completo y sync no se especifica la conversión, el bloque de salida resultante tendrá el mismo tamaño que el bloque de entrada.

Entonces esto es probablemente lo que causa su confusión. Sí, porque dd está diseñado para bloquear, por defecto parcial read() s se asignará 1:1 a write() parcial s, o bien sync d out en el relleno de la cola NUL o caracteres de espacio para bs= tamaño cuando conv=sync se especifica.

Esto significa que dd es seguro de usar para copiar datos (sin riesgo de corrupción debido a una lectura o escritura parcial) en todos los casos menos uno en el que está arbitrariamente limitado por un count= argumento, porque de lo contrario dd felizmente write() su salida en bloques de tamaño idéntico a aquellos en los que su entrada fue read() hasta que read() s completamente a través de él. E incluso esta advertencia es solo cierta cuando bs= se especifica o obs= es no especificado, como dice la siguiente oración en la especificación:

  • Si bs= expr no se especifica el operando, o una conversión que no sea sync , noerror , o notrunc se solicita, la entrada se procesará y reunirá en bloques de salida de tamaño completo hasta que se alcance el final de la entrada.
Relacionado:Debian:¿pérdida recurrente de conectividad inalámbrica?

Sin ibs= y/o obs= argumentos esto no puede importar, porque ibs y obs ambos tienen el mismo tamaño por defecto. Sin embargo, puede ser explícito sobre el almacenamiento en búfer de entrada especificando diferentes tamaños para cualquiera y no especificando bs= (porque tiene prioridad) .

Por ejemplo, si lo hace:

IN| dd ibs=1| OUT

…entonces un POSIX dd write() en fragmentos de 512 bytes recopilando cada uno read() byte en un único bloque de salida.

De lo contrario, si lo haces...

IN| dd obs=1kx1k| OUT

…un POSIX dd read() al máximo 512 bytes a la vez, pero write() cada bloque de salida del tamaño de un megabyte (permitiendo el núcleo y posiblemente exceptuando el último, porque eso es EOF) en su totalidad mediante la recopilación de entrada en bloques de salida de tamaño completo .

Sin embargo, también de la especificación:

  • count=n
    • Copiar solo n bloques de entrada.

count= asigna a i?bs= bloques, y así poder manejar un límite arbitrario en count= de forma portátil necesitarás dos dd s. La forma más práctica de hacerlo con dos dd s es canalizando la salida de uno a la entrada de otro, lo que seguramente nos coloca en el ámbito de leer/escribir un archivo especial independientemente del tipo de entrada original.

Una canalización IPC significa que al especificar [io]bs= argumenta que, para hacerlo de manera segura, debe mantener dichos valores dentro del PIPE_BUF definido por el sistema límite. POSIX establece que el kernel del sistema solo debe garantizar read() atómico s y write() s dentro de los límites de PIPE_BUF como se define en limits.h . POSIX garantiza que PIPE_BUF ser al menos

  • {_POSIX_PIPE_BUF}
    • Número máximo de bytes que se garantiza que sean atómicos al escribir en una canalización.
    • Valor:512

(que también resulta ser el dd predeterminado tamaño de bloque de E/S) , pero el valor real suele ser de al menos 4k. En un sistema linux actualizado es, por defecto, 64k.

Así que cuando configuras tu dd procesos debes hacerlo en un bloque factor basado en tres valores:

  1. bs =( obs =PIPE_BUF o menos)
  2. n =número total deseado de bytes leídos
  3. cuenta =n/bs

Me gusta:

yes | dd obs=1k | dd bs=1k count=10k of=/dev/null
10240+0 records in
10240+0 records out
10485760 bytes (10 MB) copied, 0.1143 s, 91.7 MB/s

Tienes que sincronizar i/o con dd para manejar entradas no buscables. En otras palabras, haga explícitos los pipe-buffers y dejarán de ser un problema. Eso es lo que dd es para. La cantidad desconocida aquí es yes el tamaño del búfer, pero si lo bloquea a un conocido cantidad con otro dd entonces una pequeña multiplicación informada puede hacer dd seguro de usar para copiar datos (sin riesgo de corrupción debido a una lectura o escritura parcial) incluso cuando se limita arbitrariamente la entrada con count= con cualquier tipo de entrada arbitrario en cualquier sistema POSIX y sin perder un solo byte.

Aquí hay un fragmento de la especificación POSIX:

  • ibs= expr
    • Especifique el tamaño del bloque de entrada, en bytes, mediante expr (el valor predeterminado es 512) .
  • obs= expr
    • Especifique el tamaño del bloque de salida, en bytes, mediante expr (el valor predeterminado es 512) .
  • bs= expr
    • Establezca los tamaños de bloque de entrada y salida en expr bytes, reemplazando ibs= y obs= . Si no hay otra conversión que no sea sync , noerror y notrunc se especifica, cada bloque de entrada se copiará en la salida como un solo bloque sin agregar bloques cortos.
Relacionado:¿Cómo hacer que la terminal muestre [correo electrónico protegido] en negrita?

También encontrará algo de esto mejor explicado aquí.


Linux
  1. Lea y escriba datos desde cualquier lugar con redirección en la terminal de Linux

  2. Utilice el comando Netcat para leer y escribir datos en la red en Ubuntu 20.04

  3. En Bash, ¿cuándo alias, cuándo escribir y cuándo escribir una función?

  4. ¿Cambiar el permiso para leer, escribir y ejecutar?

  5. ¿Cuándo debo usar TCP_NODELAY y cuándo TCP_CORK?

Cómo usar el comando Netcat para leer y escribir datos en la red

Trucos y tratos para administradores de sistemas y operaciones

Cómo instalar y usar Okteta para archivos de datos RAW en Linux

Anuncios de texto de pago por clic para abogados y procuradores

¿Qué es una base de datos distribuida y para qué sirven los sistemas de datos distribuidos?

Los 15 mejores programas econométricos y estadísticos para el sistema Linux