Forum Linux.général cat et dd

Posté par  .
Étiquettes : aucune
-1
3
sept.
2011

Bonjour,

Je suis en train d'écrire un script et le résultat n'est pas bon. J'ai trouvé où est situé le problème mais je ne comprends pas pourquoi ça coince. Et je ne sais pas comment contourner.

J'ai le code suivant:

(
    cat fichier1
    cat fichier2
    cat fichier3
) | lzop --decompress --to-stdout | (
        dd of=/dev/sdb  bs=100M count=290      seek=0
        dd of=/dev/null bs=100M count=25       seek=290
        dd of=/dev/sdb  bs=100M count=1        seek=315
        dd of=/dev/null bs=100M count=709      seek=316
        dd of=/dev/sdb  bs=100M count=31       seek=1025
)

# --> ce qui est écrit par dd n'a pas la bonne taille.

 

Je peux reproduire l'erreur avec un code plus simple:

dd if=/dev/urandom of=source bs=1M count=10
cat source | dd  of=dest bs=3000KB count=1
# --> 0+1 enregistrements lus
# --> 0+1 enregistrements écrits
# --> 98304 octets (98 kB) copiés, 0,000621797 s, 158 MB/s

cat source | dd  of=dest bs=300KB count=1
# --> 0+1 enregistrements lus
# --> 0+1 enregistrements écrits
# --> 131072 octets (131 kB) copiés, 0,000467747 s, 280 MB/s

# autre exemple:
cat /dev/urandom | dd of=/dev/null bs=3000KB count=1
# --> ce qui donne entre 4kio et 30kio écrits suivant la machine que j'utilise.

 

Franchement je ne pige pas ce qui cloche.
Je n'ai jamais eu de problème avec dd. A priori c'est à cause de l'utilisation de la pipe sur l'entrée standard de dd, mais je bloque là.

  • # À vue de nez…

    Posté par  . Évalué à 3.

    1. Pourquoi utilises-tu trois « cat » successifs dans un bloc ? « cat » signifie « catenate » et sert justement à concaténer plusieurs fichiers. Utilise plutôt « cat fichier1 fichier2 fichier3 » et vire les parenthèses ;

    2. Si tu lis tes données depuis l'entrée standard, il faut enlever les clauses « seek ». Tu ne relis pas, à chaque fois, le même fichier depuis le début, tu lis les données qui te parviennent les unes après les autres. Le début de ton fichier a donc déjà été « consommé » par les commandes « dd » précédentes.

    • [^] # Re: À vue de nez…

      Posté par  . Évalué à 1.

      Je retire le point numéro 2. J'ai confondu « seek » et « skip ».

      • [^] # Re: À vue de nez…

        Posté par  . Évalué à 1.

        Pour le point 2 j'avais bien vu que tu n'avais pas vu.

        Pour le cat, c'est qu'en fait il y a des commandes entre chaque fichier. Les fichiers sont sur des DVD différents. Il faut afficher un message, attendre la validation, monter, etc.

  • # taille de la pipe

    Posté par  (site Web personnel) . Évalué à -1.

    C'est effectivement lié au pipe. en utilisant l'entrée standard sans pipe, ça marche très bien ( dd ... < source)

    je suggere la lecture du man pipe(7) notamment Pipe Capacity
    je pense que ça vient de ça

    • [^] # Re: taille de la pipe

      Posté par  . Évalué à 2.

      Les processus qui écrivent dans un pipe déjà plein sont bloqués (sauf réglage volontaire de la part du programmeur). Cela permet de faire bosser ensemble des processus qui ne traitent pas les données à la même vitesse.

      Exemples dans le man de lzop:

      cat a.c │ lzop > y.lzo
      lzop -d < y.tar.lzo │ tar -xvf -
      tar -cf - *.c │ lzop > y.tar.lzo
      
      

      Il y a peu de chance que sur un gros fichier l'un des processus ne soit pas en attente.

      On peut même exagérer en faisant

      find / -print | ( while true; do dd bs=1 count=1 2>/dev/null; sleep 0.1; done)
      
      
      • [^] # Re: taille de la pipe

        Posté par  . Évalué à 2.

        Vu ma réponse plus bas, c'est bel et bien un problème de vitesse pour générer les données par rapport à celle pour les consommer.
        C'est bien spécifique à dd. Je vais matter le source pour savoir si c'est un bug ou pas.

        Je remarque que les anciennes versions n'ont pas l'option iflag=fullblock

  • # C'est dd qui merde

    Posté par  . Évalué à 3.

    Je viens de faire le test sur plusieurs machines. Toutes des Debian ou dérivées. C'est clairement dd qui merde.

    Le traitement des options bs et count semble foireux.

    Exemples censés donner 3Mio:

    $ cat /dev/urandom | dd of=dest bs=30K count=100
    # donne 1,6Mo
    
    $ cat /dev/urandom | dd of=dest bs=300K count=10
    # donne 328Ko
    
    $ cat /dev/urandom | dd of=dest bs=3000K count=1
    # donne 33Ko
    
    $ cat /dev/urandom | dd of=dest bs=10240 count=300
    # donne 2,5Mo
    
    

    La même chose mais qui fonctionne:

    $ cat /dev/urandom | dd of=dest bs=1K count=3000
    # donne 3Mio
    
    $ cat /dev/urandom | dd of=dest bs=1024 count=3000
    # donne 3Mio
    
    $ cat /dev/urandom | dd of=dest bs=2K count=1500
    # donne 3Mio
    
    

    Je remarque que les informations affichées par dd sont inhabituelles.
    Lorsque tout va bien:
    3000+0 enregistrements lus
    3000+0 enregistrements écrits
    3072000 octets (3,1 MB) copiés, 1,48802 s, 2,1 MB/s

    Lorsque ça ne fonctionne pas:
    225+75 enregistrements lus
    225+75 enregistrements écrits
    2457600 octets (2,5 MB) copiés, 1,17842 s, 2,1 MB/s

    • [^] # Re: C'est dd qui merde

      Posté par  . Évalué à 4.

      Ça me tracasse cette histoire :-)

      J'ai trouvé ce que signifient les valeur après le signe +. Ce sont les blocs lus/écrits qui ne font pas la taille demandée.
      dd est censé lire en mode bloquant, mais visiblement pas pour les pipes.

      Pour contourner le problème:
      cat /dev/urandom | dd of=dest bs=3000K count=1 iflag=fullblock

      • [^] # Re: C'est dd qui merde

        Posté par  . Évalué à 1.

        C'est effectivement ça !

        J'ai lu le source. Il n'y a rien dedans pour lire de manière bloquante si fullblock n'est pas utilisé. Ni pour les pipes ni pour le reste.
        Alors question: comment est-ce possible que copier un disque lent vers plus rapide ne pose pas de problème ?

        dd if=/dev/sdb of=/dev/sdc bs=1M
        
        

        Ca a toujours marché ce truc. Finalement ça n'aurait pas dû puisque les lectures ne sont pas bloquantes. Donc j'ai raté un truc.
        Ou alors ça veut dire que les pipes sont par défaut non bloquantes, et que les fichiers oui ? Vu que dd ne modifie pas ces paramètres, ça se tient.
        • [^] # Re: C'est dd qui merde

          Posté par  . Évalué à 4.

          Les pipes sont bien bloquants… s'il n'y a rien à lire dedans ! Mais si on fait un appel read() dessus en passant la taille d'un buffer par exemple et qu'il y a bien des caractères disponibles mais qu'il n'y a pas le compte, alors l'appel va ressortir en renvoyant le nombre de caractères qu'il a réussi à lire.

          Lorsqu'on exploite directement le disque ou un fichier, la question ne se pose pas. Les caractères sont forcément disponibles et c'est directement dd (ou n'importe quel programme à sa place) qui va aller chercher les données, par l'intermédiaire du pilote. Il n'y a qu'en cas de fin de fichier ou d'erreur que le bloc à lire peut être incomplet.

          Par contre, dans le cas d'un pipe, c'est entièrement au bon vouloir du processus écrivain qui, par définition, a un comportement asynchrone et versatile.

        • [^] # Re: C'est dd qui merde

          Posté par  . Évalué à -1.

          comment est-ce possible que copier un disque lent vers plus rapide ne pose pas de problème ?

          parce que la lecture lente permet d'avoir un buffer vide (bloquant) et pas un buffer plein (non bloquant dans les exemples au dessus)

          ce serait l'inverse qui pourrait etre problematique, copier un disque rapide vers un disque plus lent.

          mais si tu n'utilises pas les pipes comme avec un simple dd if=... of=... tu n'as aucun probleme puisque c'est dd qui se debrouille tout seul, il n'y a pas de pipe ou alors juste internes.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n’en sommes pas responsables.