dd vs cat – ¿todavía es relevante en estos días?

Recientemente me di count de que podemos usar cat tanto como dd , y en realidad es más rápido que dd

Sé que dd fue útil para tratar cintas donde el tamaño del bloque realmente importaba en la corrección, no solo el performance. En estos días, sin embargo, ¿hay situaciones en las que dd pueda hacer algo que el cat no puede? (Aquí consideraría que una diferencia de performance inferior al 20% es irrelevante).

¡Ejemplos concretos serían buenos!

En apariencia, dd es una herramienta de un sistema operativo IBM que conserva su apariencia externa (su paso de parameters), que realiza algunas funciones muy raramente usadas (como EBCDIC a conversiones ASCII o inversión de endianidad … que actualmente no es una necesidad común).

Solía ​​pensar que dd era más rápido para copyr grandes bloques de datos en el mismo disco (debido al uso más eficiente del almacenamiento en búfer), pero esto no es cierto , al less en los sistemas Linux de hoy.

Creo que algunas de las opciones de dd son útiles cuando se trata de cintas, donde la lectura realmente se realiza en bloques (los controlleres de cinta no ocultan los bloques en el medio de almacenamiento como lo hacen los controlleres de disco). Pero no sé los detalles.

Una cosa que puede hacer dd que no puede (fácilmente) hacer cualquier otra herramienta POSIX es tomar los primeros N bytes de una secuencia. Muchos sistemas pueden hacerlo con head -c 42 , pero head -c , aunque es común, no está en POSIX (y no está disponible hoy en día, por ejemplo, en OpenBSD). ( tail -c es POSIX.) Además, incluso cuando existe head -c , podría leer demasiados bytes de la fuente (porque usa internamente el buffer de stdio), que es un problema si estás leyendo desde un file especial donde solo la lectura tiene un efecto. (Los coreutils de GNU actuales leen el recuento exacto con head -c , pero FreeBSD y NetBSD usan stdio).

De manera más general, dd proporciona una interfaz para la API de files subyacente que es única entre las herramientas de Unix: solo dd puede sobreescribir o truncar un file en cualquier punto o search en un file. (Esta es la habilidad única de dd , y es muy grande; curiosamente, dd es más conocido por las cosas que otras herramientas pueden hacer).

  • La mayoría de las herramientas de Unix sobrescriben su file de salida, es decir, borran su contenido y lo reinician desde cero. Esto es lo que sucede cuando usas > networkingirección en el shell también.
  • Puede agregar los contenidos de un file con >> networkingirección en el shell o con tee -a .
  • Si desea acortar un file eliminando todos los datos después de cierto punto , esto es respaldado por el kernel subyacente y la API de C a través de la function de truncate , pero no expuesto por ninguna herramienta de command-line excepto dd :

     dd if=/dev/null of=/file/to/truncate seek=1 bs=123456 # truncate file to 123456 bytes 
  • Si desea sobrescribir datos en el medio de un file, de nuevo, esto es posible en la API subyacente abriendo el file para escritura sin truncar (y llamando a lseek para moverse a la position deseada si es necesario), pero solo dd puede abrir un file. file sin truncar o agregar, o search desde el shell ( ejemplo más complejo ).

     # zero out the second kB block in the file (ie bytes 1024 to 2047) dd if=/dev/zero of=/path/to/file bs=1024 seek=1 count=1 conv=notrunc 

Entonces … Como una herramienta de sistema, dd es bastante inútil. Como una herramienta de procesamiento de text (o file binary), ¡es bastante valioso!

El command dd incluye MUCHAS opciones que cat no puede acomodar. Quizás en sus casos de uso, cat es un sustituto viable, pero no es un reemploop dd.

Un ejemplo sería usar dd para copyr parte de algo pero no todo. Quizás desee extraer algunos de los bits del medio de una image iso o la tabla de particiones de un disco duro basado en una location conocida en el dispositivo. Con dd puede especificar las opciones de inicio, detención y cantidad que permiten estas acciones.

Estas opciones de dd hacen indispensable para la manipulación de datos de grano fino, mientras que cat * solo puede operar en objects, dispositivos o flujos de files completos.

* Como señaló Gilles en los comentarios, es posible combinar cat con otras herramientas para aislar partes de algo, pero cat aún opera en todo el object.

Nadie ha mencionado aún que se pueda usar dd para crear files dispersos , aunque truncate también se puede usar para el mismo propósito.

 dd if=/dev/zero of=sparse-file bs=1 count=1 seek=10GB 

Esto es casi instantáneo y crea un file grande arbitrario que se puede usar como un file loopback, por ejemplo:

 loop=`losetup --show -f sparse-file` mkfs.ext4 $loop mkdir myloop mount $loop myloop 

Lo bueno es que inicialmente solo usa un solo bloque de espacio de disco y, a partir de ese momento, crece solo según sea necesario (el formatting ext4 de un file de 10 GB consume 291 MB en mi sistema). Use du para ver cuánto espacio de disco se usa en realidad: solo informa el tamaño máximo que puede tener el file.

Sobrescribir segmentos específicos de un disco duro con algo es un ejemplo común. Por ejemplo, es posible que desee eliminar su MBR con este command:

 dd if=/dev/zero of=/dev/sda bs=446 count=1 

También puede crear files vacíos con él (por ejemplo, para imágenes de discos de bucle):

 dd if=/dev/zero of=10mb.file bs=1024k count=10 

dd es muy útil para hacer una copy de security del sector de arranque de un disco duro u otro dispositivo de almacenamiento ( dd if=/dev/sda of=boot_sector.bin bs=512 count=1 ) y luego reescribirlo ( dd if=boot_sector.bin of=/dev/sda ). Es similarmente útil para realizar copys de security de los encabezados de los volúmenes encryptions.

cat podría ser capaz de hacerlo, pero no confiaría en la parte de la reescritura. Es difícil hacer que cat solo lea / escriba una cierta cantidad de bytes.

Hace poco tuve motivos para clonar algunas particiones de más de 100 GB de GB por primera vez en mi historial de linuxing (cf cp -ar o rsync que me han servido muchas veces). Por supuesto, recurrí a él porque todos saben que eso es lo que usas … y estaba horrorizado por el performance. Un poco de google pronto me llevó a ddrescue , que he usado algunas veces y funciona magníficamente bien (mucho más rápido que dd).

Aquí hay algunos trucos con los que me he metido a lo largo de los años.

Cortar y pegar en modo tty hostil o modo no interactivo bash

Si se encuentra en una situación en la que no se detecta EOF / ^ D / ^ F, puede usar dd para transferir files de text a un host. Ya que dejará de leer automáticamente después de una cantidad específica de bytes.

Lo usé tan recientemente como el año pasado durante un ejercicio de security en el que pudimos get shells que no sean tty en un host remoto y necesitábamos transferir files.

De hecho, incluso hice un par de files binarys con base64 codificándolos y usando una secuencia de commands de deencoding base-base basta pero lenta pero confiable.

 dd of=textfile.txt bs=1 count=<size_of_data_in_paste_buffer> 

Un truco genial es que mientras dd se está ejecutando, si le envía una señal USR1, emitirá su estado actual (bytes leídos, bytes por segundo …)

Filtro de estado de performance universal

Escribí esto para actuar como un filter de progreso bash puro para cualquier progtwig que emita datos a través de stdout. (Nota: casi cualquier cosa emitirá datos a través de stdout; para los progtwigs que no lo hacen, puedes hacer trampa si no te molestan usando / dev / stdout como nombre de file. Pero la idea es básicamente, cada vez que obtienes X cantidad de bytes, imprimir marcas de almohadilla (como el FTP de la vieja escuela cuando tenía activado el modo hash)

(Nota) Lo del file de progreso es cojo, esto fue principalmente una testing de concepto. Si lo networkingirige, solo usaría una variable.

  dd bs=$BLKSZ of=${TMPFILE} 2>&1 \ | grep --line-buffenetworking -E '[[:digit:]]* bytes' \ | awk '{ print $1 }' >> ${PROGRESS} & while [[ $(pidof dd) -gt 1 ]]; do # PROTIP: You can sleep partial seconds sleep .5 # Force dd to update us on it's progress (which gets # networkingirected to $PROGRESS file. pkill -USR1 dd local BYTES_THIS_CYCLE=$(tail -1 $PROGRESS) local XFER_BLKS=$(((BYTES_THIS_CYCLE-BYTES_LAST_CYCLE)/BLKSZ)) if [ $XFER_BLKS -gt 0 ]; then printf "#%0.s" $(seq 0 $XFER_BLKS) BYTES_LAST_CYCLE=$BYTES_THIS_CYCLE fi done 

files de cortar y tirar utilizando anónimos manejadores de files de shell

Aquí hay un ejemplo extremadamente pseudocódigo de cómo puede tener un file tar firmado que puede extraer sin errores al proporcionar input de tar a través de un identificador de file anónimo, sin usar ningún file tmp para almacenar datos de files parciales.

 generate_hash() { echo "yay!" } # Create a tar file, generate a hash, append it to the end tar -cf log.tar /var/log/* 2>/dev/null TARFILE_SIZE=$(stat -f "%z" log.tar) SIGNATURE=$(generate_hash log.tar) echo $SIGNATURE >>log.tar # Then, later, extract without getting an error.. tar xvf <(dd if=$OLDPWD/log.tar bs=1 count=${TARFILE_SIZE}) 

El tl; dr es: Encuentro que dd es increíblemente útil. Y estos son solo los tres ejemplos en los que puedo pensar fuera de mi cabeza.