dd vs cat - le dd est-il toujours d'actualité?

122

J'ai récemment réalisé que nous pouvions utiliser catautant que dd, et c'est en fait plus rapide quedd

Je sais que cela a ddété utile pour traiter les bandes où la taille du bloc importait réellement, pas seulement la performance. De nos jours, cependant, y a-t-il des situations où ddon peut faire quelque chose ne catpeut pas? (Dans ce cas, une différence de performance inférieure à 20% serait sans importance.)

Des exemples concrets seraient bien!

kizzx2
la source
1
Voir cette question SO pour un exemple concret.
camh

Réponses:

156

En apparence, ddest un outil d’un système d’exploitation IBM qui conserve son apparence étrangère (son passage de paramètres), qui exécute des fonctions très rarement utilisées (telles que les conversions EBCDIC en ASCII ou l’inversion d’endianisme… n’est plus un besoin courant de nos jours).

J'avais l' habitude de penser que ddc'était plus rapide pour copier de gros blocs de données sur le même disque (grâce à une utilisation plus efficace de la mise en mémoire tampon), mais ce n'est pas vrai , du moins sur les systèmes Linux actuels.

Je pense que certaines des ddoptions de sont utiles pour les bandes, où la lecture se fait en bloc (les pilotes de bande ne cachent pas les blocs sur le support de stockage comme le font les pilotes de disque). Mais je ne connais pas les détails.

Une chose à ddfaire qui ne peut (facilement) être réalisée par aucun autre outil POSIX est de prendre les N premiers octets d’un flux. Beaucoup de systèmes peuvent le faire avec head -c 42, mais head -c, bien que commun, ce n'est pas dans POSIX (et n'est pas disponible aujourd'hui par exemple sur OpenBSD). ( tail -cis POSIX.) De plus, même là où il head -cexiste, il risque de lire trop d'octets de la source (car il utilise la mise en tampon stdio en interne), ce qui pose un problème si vous lisez un fichier spécial dans lequel la lecture a un effet. (Les coreutils actuels de GNU lisent le nombre exact avec head -c, mais FreeBSD et NetBSD utilisent stdio.)

Plus généralement, dddonne une interface à l'API de fichier sous-jacente unique parmi les outils Unix: seuls ddpeuvent écraser ou tronquer un fichier à tout moment ou rechercher dans un fichier. (C’est ddune capacité unique et elle est importante; curieusement, elle ddest mieux connue pour ce que d’autres outils peuvent faire.)

  • La plupart des outils Unix écrasent leur fichier de sortie, c’est-à-dire effacent son contenu et le redémarrent à partir de zéro. C'est ce qui se produit lorsque vous utilisez également la >redirection dans le shell.
  • Vous pouvez ajouter au contenu d'un fichier avec une >>redirection dans le shell ou avec tee -a.
  • Si vous souhaitez raccourcir un fichier en supprimant toutes les données après un certain point , cela est pris en charge par le noyau sous-jacent et l'API C via la truncatefonction, mais n'est exposé par aucun outil de ligne de commande, à l' exception des éléments suivantsdd :

    dd if=/dev/null of=/file/to/truncate seek=1 bs=123456  # truncate file to 123456 bytes
    
  • Si vous souhaitez écraser des données au milieu d'un fichier, cela est à nouveau possible dans l'API underyling en ouvrant le fichier en écriture sans le tronquer (et en appelant lseekpour vous déplacer si nécessaire), mais vous ddpouvez uniquement ouvrir un fichier sans tronquer ou ajouter, ou chercher dans le shell ( exemple plus complexe ).

    # 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
    

Alors… En tant qu'outil système, ddc'est quasiment inutile. En tant qu'outil de traitement de texte (ou de fichier binaire), il est très utile!

Gilles
la source
Accepté parce que je pense que cela explique l'essentiel des autres réponses ( truncet qu'il seekest utilisable depuis dd).
kizzx2
2
Une autre utilisation spéciale: ddpeut lire des données binaires à partir de descripteurs de fichiers non lisibles sans potentiellement détruire les données non lues en raison de la mise en mémoire tampon stdio Voir ici pour un exemple: etalabs.net/sh_tricks.html
R ..
2
@R ..: Oui. Dans GNU coreutils 6.10, head -c Nappelle readet ne dépasse jamais N. Dans NetBSD 5.1, head -cappelle getc. Dans FreeBSD 7.4, head -cappelle fread.
Gilles
1
Coreutils ddexpose également O_DIRECT (etc.) pour les scripts shell, qui je pense est également unique.
derobert
1
Coreutils truncatepermet de tronquer ou d'étendre des fichiers, éliminant ainsi une autre utilisation de dd.
Décembre
22

La ddcommande inclut BEAUCOUP d’options que cat ne peut pas prendre en charge. Peut-être que dans vos cas d'utilisation, cat est un substitut utilisable, mais ce n'est pas un substitut du DD.

Un exemple serait d'utiliser ddpour copier une partie de quelque chose mais pas le tout. Peut-être voudrez-vous extraire certains des bits du milieu d'une image ISO ou de la table de partition d'un disque dur en fonction d'un emplacement connu sur le périphérique. Avec, ddvous pouvez spécifier les options de démarrage, d'arrêt et de quantité permettant ces actions.

Ces options ddrendent indispensable la manipulation de données à granulométrie fine, alors que cat* ne peut fonctionner que sur des objets, périphériques ou flux de fichiers entiers.

* Comme l’a noté Gilles dans les commentaires, il est possible de combiner catavec d’autres outils pour isoler des parties de quelque chose, mais catfonctionne toujours sur l’objet entier.

Caleb
la source
5
ddn’a en fait rien à voir avec les périphériques de bas niveau, il a besoin d’une entrée /devcomme les autres. Vous pouvez copier une partition entière catou une partie de celle-ci avec tail +c $(($start+1)) | head -c $count.
Gilles
16
Bien sûr. ;-) Et quand j'alimente une image disque de 1,6 To cat | head | tailpour récupérer les derniers MB, le disque qui tourne aspire la lune plus près de la Terre.
Caleb
2
@Gilles Désolé, je voulais avouer que mon utilisation du terme "bas niveau" n'était pas une très bonne diction, même si je faisais référence à des données stockées sur des appareils et non à des appareils. Peut-être qu'une "manipulation de données ajustée" serait préférable à une "manipulation de données de bas niveau".
Caleb
21

Personne n’a encore indiqué que vous pouvez utiliser dd pour créer des fichiers fragmentés , même s’ils truncatepeuvent également être utilisés aux mêmes fins.

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

Ceci est presque instantané et crée un fichier volumineux arbitraire qui peut être utilisé comme fichier de bouclage, par exemple:

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

La bonne chose est qu’elle n’utilise au départ qu’un seul bloc d’espace disque, puis ne croît que si nécessaire (le formatage ext4 d’un fichier de 10 Go consomme 291 Mo sur mon système). Utilisez cette option dupour voir la quantité réellement utilisée d'espace disque. lsIndique uniquement la taille maximale du fichier.

Lauritz V. Thaulow
la source
4
ls -lsvous montre la taille clairsemée.
Jmtd
2
Votre commande écrit un octet inutile dans le fichier. dd of=sparse-file bs=1 count=0 seek=10Gserait équivalent à truncate -s 10GB sparse-file. Assez de prêter à confusion, truncateet ddont l' interprétation exacte opposé de GBcontre G...
Frostschutz
5
@frostschutz: man dddit: MB =1000*1000, M =1024*1024et ainsi de suite. Et man truncatedit: MB 1000*1000, M 1024*1024Donc, il n'y a pas de différence. J'utilise les deux ddet truncatede la coreutils GNU. Tu devrais le faire aussi! :-)
erik
@erik: Merci pour la correction. Si cela n'a pas été changé récemment, j'ai dû le confondre avec quelque chose d'autre.
Frostschutz
10

Remplacer des segments spécifiques d’un disque dur par quelque chose est un exemple courant. Par exemple, vous voudrez peut-être supprimer votre MBR à l'aide de cette commande:

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

Aussi, vous pouvez créer des fichiers vides avec (par exemple pour les images de disque en boucle):

dd if=/dev/zero of=10mb.file bs=1024k count=10
XQYZ
la source
En passant, ce second commandement est le moyen le plus rapide que je connaisse pour utiliser 10 Mo
Kevin M -
3
@ Kevin: Plus rapide que head -c? S'il vous plaît partager un point de repère !
Gilles
9

ddest très utile pour sauvegarder le secteur de démarrage d'un disque dur ou d'un autre périphérique de stockage ( dd if=/dev/sda of=boot_sector.bin bs=512 count=1), puis pour le réécrire ultérieurement ( dd if=boot_sector.bin of=/dev/sda). Il est également utile pour la sauvegarde des en-têtes de volumes chiffrés.

catpourrait être capable de le faire mais je n’aurais pas confiance en la partie réécriture. Il est difficile de catne lire / écrire qu'un certain nombre d'octets.

LawrenceC
la source
5

J'avais récemment eu raison de cloner des partitions de plusieurs centaines de Go pour la première fois de mon histoire de linuxing (cf cp -arou rsyncqui m'ont bien servi à plusieurs reprises). Bien sûr, je me suis tourné vers dd«parce que tout le monde sait que c'est ce que vous utilisez ... et j'ai été choqué par la performance. Un peu de googler m’a bientôt conduit ddrescue, que j’ai utilisé plusieurs fois et qui fonctionne très bien (beaucoup plus vite que dd).

timday
la source
1
ddrescueest formidable, notamment pour extraire des données de disques défaillants.
Ryenus
5

Voici quelques astuces que j'ai trouvées au fil des ans.

Couper-coller en mode non-interactif ou non-interactif bash

Si vous êtes dans une situation où EOF / ^ D / ^ F n'est pas détecté, vous pouvez utiliser dd pour transférer des fichiers texte sur un hôte. Puisqu'il arrêtera de lire automatiquement après une quantité d'octets spécifiée.

Je l’utilisais aussi récemment que l’année dernière lors d’un exercice de sécurité au cours duquel nous pouvions obtenir des shells non-tty sur un hôte distant et que nous devions transférer des fichiers.

En fait, j'ai même créé quelques fichiers binaires en les encodant en base64 et en utilisant un script de décodage base64 lent-fiable, mais fiable.

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

Une astuce géniale est que pendant que dd est en cours d’exécution, si vous lui envoyez un signal USR1, il émettra son statut actuel (octets lus, octets par seconde, etc.).

Filtre d'état de débit universel

J'ai écrit ceci pour agir comme un filtre de progrès pur bash pour tout programme qui émet des données via stdout. (Remarque: à peu près tout ce qui émettra des données via stdout - pour les programmes qui ne le font pas, vous pouvez tricher s'ils ne vous critiquent pas en utilisant / dev / stdout en tant que nom de fichier. Mais l'idée est fondamentalement que chaque fois que vous obtenez X nombre d'octets, marques de hachage d'impression (comme l'ancien FTP de l'école lorsque le mode de hachage était activé)

(Note) Le dossier de progression est boiteux, c'était principalement une preuve de concept. Si je le refais, je n'utiliserais qu'une 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

fichiers slice-and-dice utilisant des descripteurs de fichiers shell anonymes

Voici un exemple extrêmement pseudo-code de la manière dont vous pouvez obtenir un fichier tar signé que vous pouvez extraire sans erreur en fournissant une entrée tar via un descripteur de fichier anonyme - sans utiliser de fichier tmp pour stocker des données de fichier partielles.

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})

Le tl; dr est: je trouve que dd est incroyablement utile. Et ce ne sont que les trois exemples auxquels je peux penser de façon spontanée.

synthétiseurpatel
la source
4

Vous pouvez rediriger certains contenus de sortie. C'est particulièrement utile si vous avez besoin d'écrire avec sudo:

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

En plus sudoc'est équivalent à:

echo some_content > output.txt

ou à ceci:

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