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é à tar
cela 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 tar
est en mesure de découvrir que son fichier de sortie est /dev/null
, c'est-à-dire lorsqu'il /dev/null
est directement ouvert pour avoir le descripteur de fichier dans lequel il tar
écrit, le corps du fichier semble ignoré. (L'ajout d'une v
option pour tar
imprimer 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 tar
mê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.
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é.pv
:tar -cf - | pv >/dev/null
. Cela évite le problème et vous donne des informations sur la progression (les différentespv
options)gtar -cf /dev/zero ...
pour obtenir ce que vous aimez.Réponses:
Il s'agit d' une optimisation documentée :
la source
info tar
place ...info
ou en HTML dans un navigateur.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
read
appels 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 desread
retours) et leswrite
appels (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) etsendfile
(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/null
et transforme l'appel système en no-opLes programmes peuvent utiliser
mmap
pour obtenir le contenu du fichier au lieu deread
, 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 peutmmap
le fichier source, puis faire appelwrite
à ce morceau de mémoire mappée. Cependant, comme l'écriture/dev/null
n'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/null
lieu de> /dev/null
- et pourquoi| cat > /dev/null
devrait être évité dans tous les autres cas.la source
tar
page 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érifiertar cf /dev/null foo*
quelques fichiers et oui, juste desnewfstatat(..., AT_SYMLINK_NOFOLLOW)
appels système, pas même unopen()
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.splice(2)
sous Linux. En fait, le remplacementcat > /dev/null
depv -q > /dev/null
(qui utilisesplice()
sous Linux) réduirait probablement les frais généraux. Oudd bs=65536 skip=9999999999 2> /dev/null
, ouwc -c > /dev/null
outail -c1 > /dev/null
...