Pourquoi tar semble-t-il ignorer le contenu du fichier lorsque le fichier de sortie est / dev / null?

21

J'ai un répertoire contenant plus de 400 Gio de données. Je voulais vérifier que tous les fichiers peuvent être lus sans erreur, alors j'ai pensé à tarcela de manière simple /dev/null. Mais à la place, je vois le comportement suivant:

$ time tar cf /dev/null .

real    0m4.387s
user    0m3.462s
sys     0m0.185s
$ time tar cf - . > /dev/null

real    0m3.130s
user    0m3.091s
sys     0m0.035s
$ time tar cf - . | cat > /dev/null
^C

real    10m32.985s
user    0m1.942s
sys     0m33.764s

La troisième commande ci-dessus a été arrêtée de force par Ctrl+ Caprès avoir déjà couru assez longtemps. De plus, alors que les deux premières commandes fonctionnaient, l'indicateur d'activité du périphérique de stockage contenant .était presque toujours inactif. Avec la troisième commande, l'indicateur est constamment allumé, ce qui signifie une activité extrême.

Il semble donc que, lorsqu'il tarest en mesure de découvrir que son fichier de sortie est /dev/null, c'est-à-dire lorsqu'il /dev/nullest directement ouvert pour avoir le descripteur de fichier dans lequel il tarécrit, le corps du fichier semble ignoré. (L'ajout d'une voption pour tarimprimer tous les fichiers du répertoire étant tar«rouge».)

Je me demande donc, pourquoi en est-il ainsi? Est-ce une sorte d'optimisation? Si oui, alors pourquoi voudrait-il tarmême faire une optimisation aussi douteuse pour un cas si spécial?

J'utilise GNU tar 1.26 avec glibc 2.27 sous Linux 4.14.105 amd64.

Ruslan
la source
7
Comme alternative pratique, envisagez quelque chose comme find . -type f -exec shasum -a256 -b '{}' +. Non seulement il ne fait lire et la somme de contrôle toutes les données, mais si vous stockez la sortie, vous pouvez relancer ultérieurement pour vérifier que le contenu des fichiers n'a pas changé.
Ilmari Karonen le
Pour mesurer les choses que vous pouvez également utiliser pv: tar -cf - | pv >/dev/null. Cela évite le problème et vous donne des informations sur la progression (les différentes pvoptions)
xenoid
Vous avez touché une fonction manquante bien connue de GNU tar. Utilisez gtar -cf /dev/zero ...pour obtenir ce que vous aimez.
schily

Réponses:

25

Il s'agit d' une optimisation documentée :

Lors de la création de l'archive /dev/null, GNU tar essaie de minimiser les opérations d'entrée et de sortie. Le système de sauvegarde Amanda, lorsqu'il est utilisé avec GNU tar, a une passe de dimensionnement initial qui utilise cette fonctionnalité.

muru
la source
4
Ah, cela n'était pas décrit dans la page de manuel que j'avais installée. J'aurais dû essayer à la info tarplace ...
Ruslan
9
Ils devraient vraiment garder les pages man et info synchronisées, c'est pratiquement un bug qu'ils ne sont pas
Xen2050
9
@Ruslan Avec la plupart des utilitaires GNU, la page de manuel ne contient qu'un bref résumé, fondamentalement suffisant uniquement lorsque vous vous souvenez qu'il a une option pour faire quelque chose mais ne vous souvenez pas du nom de l'option. La documentation complète est dans un format qui ne se traduit pas bien en pages de manuel et est disponible avec infoou en HTML dans un navigateur.
Gilles 'SO- arrête d'être méchant'
18
C'est un problème reconnu .
Owen
8

Cela peut se produire avec une variété de programmes, par exemple, j'ai eu ce comportement une fois lors de l'utilisation cp file /dev/null; au lieu d'obtenir une estimation de la vitesse de lecture de mon disque, la commande est revenue après quelques millisecondes.

Pour autant que je m'en souvienne, c'était sur Solaris ou AIX, mais le principe s'applique à toutes sortes de systèmes unix-y.

Dans les temps anciens, lorsqu'un programme copiait un fichier quelque part, il alternait entre les readappels qui récupèrent certaines données du disque (ou tout ce à quoi le descripteur de fichier fait référence) dans la mémoire (avec une garantie que tout est là lors des readretours) et les writeappels (qui prennent le morceau de mémoire et envoient le contenu à la destination).

Cependant, il existe au moins deux nouvelles façons d'y parvenir:

  • Linux a des appels système copy_file_range(pas portable du tout pour les autres unix) et sendfile(quelque peu portable; initialement destiné à envoyer un fichier sur le réseau, mais peut utiliser n'importe quelle destination maintenant). Ils sont destinés à optimiser les transferts; si le programme en utilise un, il est facilement concevable que le noyau reconnaisse la cible /dev/nullet transforme l'appel système en no-op

  • Les programmes peuvent utiliser mmappour obtenir le contenu du fichier au lieu de read, cela signifie essentiellement "assurez-vous que les données sont là lorsque j'essaie d'accéder à ce morceau de mémoire" au lieu de "assurez-vous que les données sont là lorsque l'appel système revient". Ainsi, un programme peut mmaple fichier source, puis faire appel writeà ce morceau de mémoire mappée. Cependant, comme l'écriture /dev/nulln'a pas besoin d'accéder aux données écrites, la condition "assurez-vous qu'elle est là" n'est jamais déclenchée, ce qui entraîne la non-lecture du fichier.

Je ne sais pas si le goudron de gnu utilise tout, et qui, de ces deux mécanismes quand il détecte qu'il est écrit /dev/null, mais ils sont la raison pour laquelle tout programme, quand il est utilisé pour vérifier en lecture des vitesses , doit être exécuté avec au | cat > /dev/nulllieu de > /dev/null- et pourquoi | cat > /dev/nulldevrait être évité dans tous les autres cas.

Guntram Blohm soutient Monica
la source
Je pense que l'implication dans la tarpage d'informations GNU (voir autre réponse) est qu'il a un mode spécial pour cela, qui présume simplement les fichiers statistiques sans les ouvrir. En fait, je viens de vérifier tar cf /dev/null foo*quelques fichiers et oui, juste des newfstatat(..., AT_SYMLINK_NOFOLLOW)appels système, pas même un open()qui pourrait mettre à jour l'heure. Mais +1 pour décrire les mécanismes où cela peut se produire sans avoir à le détecter spécialement.
Peter Cordes
L'explication mmap doit-elle se lire "accéder aux données lues " au lieu de "accéder aux données écrites "?
Wayne Conrad
Voir aussi splice(2)sous Linux. En fait, le remplacement cat > /dev/nullde pv -q > /dev/null(qui utilise splice()sous Linux) réduirait probablement les frais généraux. Ou dd bs=65536 skip=9999999999 2> /dev/null, ou wc -c > /dev/nullou tail -c1 > /dev/null...
Stéphane Chazelas