dd vs cat: ¿dd sigue siendo relevante en estos días?

122

Recientemente me di cuenta de que podemos usar cattanto como dd, y en realidad es más rápido quedd

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

¡Ejemplos concretos estarían bien!

kizzx2
fuente
1
Vea esta pregunta SO para un ejemplo concreto.
camh

Respuestas:

156

En apariencia, ddes una herramienta de un sistema operativo IBM que retiene su apariencia extraña (su paso de parámetros), que realiza algunas funciones muy raramente utilizadas (como conversiones EBCDIC a ASCII o inversión de endianness ... no es una necesidad común hoy en día).

Yo solía pensar que ddera más rápido para copiar grandes bloques de datos en el mismo disco (debido a un uso más eficiente de almacenamiento temporal), pero esto no es cierto , al menos en los sistemas Linux de hoy en día.

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

Una cosa que ddpuede hacer es que ninguna otra herramienta POSIX puede hacer (fácilmente) tomar los primeros N bytes de una secuencia. Muchos sistemas pueden hacerlo head -c 42, pero head -c, aunque son comunes, no están en POSIX (y no están disponibles hoy, por ejemplo, en OpenBSD). ( tail -ces POSIX.) Además, incluso donde head -cexista, podría leer demasiados bytes de la fuente (porque utiliza internamente el almacenamiento en búfer stdio), lo cual es un problema si está leyendo desde un archivo especial donde solo la lectura tiene un efecto. (Los coreutils actuales de GNU leen el recuento exacto head -c, pero FreeBSD y NetBSD usan stdio).

En términos más generales, ddproporciona una interfaz para la API de archivo subyacente que es única entre las herramientas de Unix: solo ddpuede sobrescribir o truncar un archivo en cualquier punto o buscar en un archivo. (Esta es dduna habilidad única, y es grande; curiosamente ddes mejor conocida por cosas que otras herramientas pueden hacer).

  • La mayoría de las herramientas de Unix sobrescriben su archivo de salida, es decir, borran su contenido y lo inician desde cero. Esto es lo que sucede cuando también usa la >redirección en el shell.
  • Puede agregar al contenido de un archivo con >>redirección en el shell, o con tee -a.
  • Si desea acortar un archivo eliminando todos los datos después de un cierto punto , esto es compatible con el núcleo subyacente y la API de C a través de la truncatefunción, pero no está expuesto por ninguna herramienta de línea de comandos, exceptodd :

    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 archivo, nuevamente, esto es posible en la API subyacente abriendo el archivo para escribir sin truncar (y llamando lseekpara moverse a la posición deseada si es necesario), pero solo ddpuede abrir un archivo sin truncar o anexar, o buscar desde el shell ( ejemplo más complejo ).

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

Entonces ... Como herramienta del sistema, ddes bastante inútil. Como herramienta de procesamiento de texto (o archivo binario), ¡es bastante valioso!

Gilles
fuente
Aceptado porque creo que explica la esencia de las otras respuestas ( truncy de seekser utilizable dd).
kizzx2
2
Un uso especial más: ddpuede leer datos binarios de descriptores de archivo no buscables sin destruir potencialmente los datos no leídos debido al almacenamiento en búfer stdio. Vea aquí para ver un ejemplo: etalabs.net/sh_tricks.html
R ..
2
@R ..: Sí. En GNU coreutils 6.10, head -c Nllamadas ready nunca va más allá de N. En NetBSD 5.1, head -cllamadas getc. En FreeBSD 7.4, head -cllamadas fread.
Gilles
1
Coreutils ddtambién expone O_DIRECT (etc.) a las secuencias de comandos de shell, que creo que también es único.
derobert
1
Coreutils truncatepermite truncar o extender archivos, eliminando así otro uso de dd.
dcoles
22

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

Un ejemplo sería usar ddpara copiar parte de algo pero no todo. Tal vez desee extraer algunos de los bits del medio de una imagen iso o de la tabla de partición desde un disco duro en función de una ubicación conocida en el dispositivo. Con ddusted puede especificar las opciones de inicio, detención y cantidad que permiten estas acciones.

Estas opciones lo ddhacen indispensable para la manipulación de datos de grano fino, mientras que cat* solo puede operar en objetos de archivos completos, dispositivos o transmisiones.

* Como señaló Gilles en los comentarios, es posible combinarlo catcon otras herramientas para aislar partes de algo, pero cataún funciona en todo el objeto.

Caleb
fuente
55
dden realidad no tiene nada que ver con dispositivos de bajo nivel, necesita una entrada /devcomo las demás. Puede copiar una partición completa con cat, o una parte de ella con tail +c $(($start+1)) | head -c $count.
Gilles
16
Por supuesto. ;-) Y cuando introduzco una imagen de disco de 1.6TB cat | head | tailpara obtener los últimos MB, el disco giratorio absorberá la luna más cerca de la tierra.
Caleb
2
@Gilles Lo siento, quise decir que reconozco que mi uso del término "nivel bajo" no fue una muy buena dicción, aunque me refería a datos en dispositivos, no en dispositivos. Quizás "mejor manipulación de datos" sería mejor que "manipular datos de bajo nivel".
Caleb
21

Nadie ha mencionado aún que puede usar dd para crear archivos dispersos , aunque truncatetambién puede usarse 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 archivo grande arbitrario que puede usarse como un archivo 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 en disco, y luego crece solo según sea necesario (el formato ext4 de un archivo de 10GB consume 291 MB en mi sistema). Úselo dupara ver cuánto espacio en disco se usa realmente: lsinforma solo el tamaño máximo que puede alcanzar el archivo.

Lauritz V. Thaulow
fuente
44
ls -lsle muestra el tamaño escaso.
jmtd
2
Su comando escribe un byte inútil en el archivo. dd of=sparse-file bs=1 count=0 seek=10Gsería equivalente a truncate -s 10GB sparse-file. Lo suficientemente confuso, truncatey ddtener una interpretación exactamente opuesta de GBvs. G...
frostschutz
55
@frostschutz: man dddice: MB =1000*1000, M =1024*1024y así sucesivamente. Y man truncatedice:, MB 1000*1000, M 1024*1024entonces no hay diferencia. Yo uso ambos ddy truncatede los coreutils de GNU. ¡Tú también deberías hacerlo! :-)
erik
@erik: Gracias por la corrección. Si no se cambió recientemente, debo haberlo confundido con algo más de alguna manera.
frostschutz
10

Reemplazar 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 comando:

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

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

dd if=/dev/zero of=10mb.file bs=1024k count=10
XQYZ
fuente
Por otro lado, ese segundo comando es la forma más rápida que conozco para usar hasta 10 MB
Kevin M
3
@ Kevin: ¿Más rápido que head -c? ¡Por favor comparta un punto de referencia !
Gilles
9

ddes muy útil para hacer una copia de seguridad 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 igualmente útil para hacer una copia de seguridad de los encabezados de los volúmenes cifrados.

catpodría ser torcido para hacer eso, pero no confiaría en la reescritura. Es difícil obtener catsolo lectura / escritura de un cierto número de bytes.

LawrenceC
fuente
5

Recientemente tuve motivos para clonar algunas particiones de varios cientos de GB por primera vez en mi historial de Linux (cf cp -aro rsyncque me han servido muchas veces). Por supuesto, recurrí a dd'porque todos saben que eso es lo que usas ... y me quedé horrorizado por el rendimiento. Un poco de búsqueda en Google pronto me llevó ddrescue, lo que he usado varias veces y funciona de maravilla (mucho más rápido que dd).

Timday
fuente
1
ddrescuees genial, especialmente para extraer datos de discos defectuosos.
ryenus
5

Aquí hay algunos trucos de dd que he inventado a lo largo de los años.

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

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

Utilicé esto tan recientemente como el año pasado durante un ejercicio de seguridad en el que pudimos obtener shells no tty en un host remoto y necesité transferir archivos.

De hecho, incluso hice un par de archivos binarios codificándolos en base64 y usando un script de decodificación de base64 puro, lento 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 rendimiento universal

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

(Nota) Lo del archivo de progreso es poco convincente, esto fue principalmente una prueba de concepto. Si lo rehizo, solo usaría una variable.

 dd bs=$BLKSZ of=${TMPFILE} 2>&1 \
                | grep --line-buffered -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
        # redirected 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

archivos de cortar y cortar dados utilizando manijas anónimas de shell

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

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 dd increíblemente útil. Y estos son solo los tres ejemplos que se me ocurren en la cabeza.

sintetizadorpatel
fuente
4

Puede redirigir parte del contenido de salida. Es particularmente útil, si necesita escribir con sudo:

echo some_content | sudo dd status=none of=output.txt

Además sudoes equivalente a:

echo some_content > output.txt

o a esto:

echo some_content | sudo tee output.txt > /dev/null
Alexey
fuente