web-dev-qa-db-fra.com

dd vs cat - dd est-il toujours d'actualité ces jours-ci?

J'ai récemment réalisé que nous pouvons utiliser cat autant que dd, et c'est en fait plus rapide que dd

Je sais que dd était utile pour traiter les bandes où la taille des blocs importait réellement en termes d'exactitude, pas seulement de performances. De nos jours, cependant, existe-t-il des situations où dd peut faire quelque chose cat ne peut pas? (Ici, je considérerais une différence de performance inférieure à 20% non pertinente.)

Des exemples concrets seraient Nice!

129
kizzx2

En apparence, dd est un outil d'un système d'exploitation IBM qui a conservé son apparence étrangère (son passage de paramètres), qui exécute certaines fonctions très rarement utilisées (comme EBCDIC pour ASCII conversions ou inversion de l'endianité… ce n'est pas un besoin courant de nos jours).

I pensait autrefois que dd était plus rapide pour copier de gros blocs de données sur le même disque (en raison d'une utilisation plus efficace de la mise en mémoire tampon), mais cela n'est pas vrai , au moins sur les systèmes Linux d'aujourd'hui.

Je pense que certaines des options de dd sont utiles lorsqu'il s'agit de bandes, où la lecture est vraiment effectuée dans des blocs (les pilotes de bande ne masquent 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 que dd peut faire et qui ne peut (facilement) être effectuée par aucun autre outil POSIX est de prendre les N premiers octets d'un courant. De nombreux systèmes peuvent le faire avec head -c 42, Mais head -c, Bien que courant, n'est pas dans POSIX (et n'est pas disponible aujourd'hui sur, par exemple, OpenBSD). (tail -c Est POSIX.) De plus, même là où head -c Existe, il peut lire trop d'octets de la source (car il utilise la mémoire tampon stdio en interne), ce qui est un problème si vous lisez à partir d'un fichier spécial où la simple 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, dd donne une interface à l'API de fichier sous-jacente unique parmi les outils Unix: seul dd peut écraser ou tronquer un fichier à tout moment ou cherche dans un fichier. (Il s'agit de la capacité unique de dd, et elle est grande; curieusement, dd est surtout connue pour les choses que d'autres outils peuvent faire.)

  • La plupart des outils Unix écrasent leur fichier de sortie, c'est-à-dire effacent son contenu et le recommencent à 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 la 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 truncate , mais non exposée par aucun outil de ligne de commande sauf dd :

    dd if=/dev/null of=/file/to/truncate seek=1 bs=123456  # truncate file to 123456 bytes
    
  • Si vous voulez écraser les données au milieu d'un fichier, encore une fois, cela est possible dans l'API de sous-traitance en ouvrant le fichier pour l'écrire sans tronquer (et en appelant lseek pour se déplacer à la position souhaitée si nécessaire), mais seulement dd peut ouvrir un fichier sans tronquer ou ajouter, ou chercher à partir du 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
    

Donc… En tant qu'outil système, dd est pratiquement inutile. En tant qu'outil de traitement de texte (ou fichier binaire), c'est très utile!

La commande dd inclut BEAUCOUP d'options que cat n'est pas en mesure d'accueillir. Peut-être que dans vos cas d'utilisation, le chat est un substitut réalisable, mais ce n'est pas un remplacement dd.

Un exemple serait d'utiliser dd pour copier une partie de quelque chose mais pas le tout. Vous souhaitez peut-être 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 dd, vous pouvez spécifier les options de démarrage, d'arrêt et de quantité qui permettent ces actions.

Ces options de dd le rendent indispensable pour une manipulation fine des données alors que cat * ne peut fonctionner que sur des objets, des périphériques ou des flux de fichiers entiers.

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

22
Caleb

Personne n'a encore mentionné que vous pouvez utiliser dd pour créer fichiers épars , bien que truncate puisse également être utilisé dans le même but.

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

C'est presque instantané et crée un gros fichier 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

Ce qui est bien, c'est qu'au départ, il n'utilise 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 du pour voir combien d'espace disque est réellement utilisé - ls indique uniquement la taille maximale du fichier.

21

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

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

Vous pouvez également créer des fichiers vides avec lui (par exemple pour les images de disque en boucle):

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

dd est 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 la réécrire ultérieurement (dd if=boot_sector.bin of=/dev/sda). Il est également utile pour sauvegarder les en-têtes des volumes chiffrés.

cat pourrait être tordu en faisant cela, mais je ne lui ferais pas confiance pour la partie réécriture. Il est difficile de faire en sorte que cat ne lise/écrive qu'un certain nombre d'octets.

9
LawrenceC

J'ai récemment eu à cloner des partitions de plusieurs centaines de Go pour la première fois de mon histoire de linuxing (c.f cp -ar ou rsync qui m'ont bien servi plusieurs fois). Bien sûr, je me suis tourné vers dd 'car tout le monde sait que c'est ce que vous utilisez ... et j'ai été consterné par la performance. Un peu de recherche sur Google m'a rapidement conduit à ddrescue , que j'ai utilisé plusieurs fois maintenant et qui fonctionne très bien (beaucoup plus rapidement que dd).

5
timday

Voici quelques trucs dd que j'ai trouvé au fil des ans ..

Couper-coller sur tty hostile ou bash en mode non interactif

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 vers un hôte. Puisqu'il arrêtera automatiquement la lecture après un nombre spécifié d'octets.

J'ai utilisé cela aussi récemment que l'année dernière lors d'un exercice de sécurité où nous avons pu obtenir des shells non tty sur un hôte distant et 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 pur mais bash pur mais fiable.

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

Une astuce super cool est que pendant l'exécution de dd, si vous lui envoyez un signal USR1, il émettra son état actuel (octets lus, octets par seconde ..)

filtre d'état de débit universel

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

(Remarque) Le fichier de progression est boiteux, c'était surtout une preuve de concept. Si je le refaisais, j'utiliserais juste 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

couper et couper des fichiers à l'aide de descripteurs de fichiers Shell anonymes

Voici un exemple extrêmement pseudo-code de la façon dont vous pouvez avoir un fichier tar signé que vous pouvez extraire sans erreurs en fournissant une entrée tar via un descripteur de fichier anonyme - sans utiliser de fichiers 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 du haut de ma tête.

5
synthesizerpatel

Vous pouvez rediriger du contenu 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

Outre Sudo, il équivaut à:

echo some_content > output.txt

ou à ceci:

echo some_content | Sudo tee output.txt > /dev/null
5
Alexey