Je comprends très bien la notion de liens physiques et j'ai lu plusieurs fois les pages de manuel des outils de base comme cp
--- et même les spécifications POSIX récentes ---. J'ai quand même été surpris d'observer le comportement suivant:
$ echo john > john
$ cp -l john paul
$ echo george > george
À ce stade, john
il paul
aura le même inode (et le même contenu) et george
différera sur les deux aspects. Maintenant, nous faisons:
$ cp george paul
A ce stade , je me attendais george
et paul
d'avoir un nombre différent de inodes , mais le même contenu --- cette attente est satisfaite --- mais je également prévu paul
d'avoir maintenant un inode différent de john
, et john
d'avoir encore le contenu john
. C'est là que j'ai été surpris. Il s'avère que la copie d'un fichier vers le chemin de destination paul
a également pour résultat d'installer ce même fichier (même inode) sur tous les autres chemins de destination qui partagent paul
l'inode. Je pensais que cela cp
crée un nouveau fichier et le déplace à la place autrefois occupée par l'ancien fichier paul
. Au lieu de cela, ce qu'il semble faire est d'ouvrir le fichier existant paul
, de le tronquer et d'écriregeorge
contenu dans ce fichier existant. Par conséquent, tous les "autres" fichiers avec le même inode obtiennent "leur" contenu mis à jour en même temps.
Ok, c'est un comportement systématique et maintenant que je sais m'y attendre, je peux trouver un moyen de contourner ce problème ou d'en tirer parti, le cas échéant. Ce qui me laisse perplexe, c'est où j'étais censé voir ce comportement documenté? Je serais surpris si ce n'est pas documenté quelque part dans des documents que j'ai déjà consultés. Mais apparemment, je l'ai manqué, et je ne trouve pas maintenant une source qui discute de ce comportement.
cp
documents qu'il écrase le fichier de destination si le fichier de destination est déjà présent. Vous avez raison, il ne spécifie pas en détail ce que signifie "écraser", mais il dit définitivement "écraser", pas "remplacer". Si vous voulez être pédant, vous pouvez affirmer que «remplacer» est exactement ce quicp
fait, et le comportement que vous attendiez serait correctement appelé «remplacer».Notez également que si
cp
"remplacer" des fichiers de destination préexistants, cela pourrait raisonnablement être considéré comme surprenant ou incorrect, probablement plus que "l'écrasement". Par exemple:cp
abord supprimé l'ancien fichier puis créé un nouveau, il y aurait un intervalle de temps pendant lequel le fichier serait absent, ce qui serait surprenant.cp
abord créé un fichier temporaire puis déplacé en place, il devrait probablement documenter cela, en raison du fait que de tels fichiers temporaires avec des noms étranges seraient parfois remarqués ... mais ce n'est pas le cas.cp
ne pouviez pas créer un nouveau fichier dans le même répertoire que l'ancien fichier en raison d'autorisations, ce serait regrettable (surtout s'il avait déjà supprimé l'ancien).cp
et que l'utilisateur en cours d'exécutioncp
ne l'était pas,root
il serait impossible de faire correspondre le propriétaire et les autorisations du nouveau fichier à ceux du nouveau fichier.cp
ne sont pas connus, ils seront perdus dans la copie. De nos jours, les implémentations decp
devraient comprendre de manière fiable des choses comme les attributs étendus, mais il n'en a pas toujours été ainsi. Et il y a d'autres choses, comme les fourchettes de ressources MacOS, ou, pour les systèmes de fichiers distants, pratiquement n'importe quoi.Donc en conclusion: maintenant vous savez ce
cp
qui fait vraiment. Vous n'en serez plus jamais surpris! Honnêtement, je pense que la même chose aurait pu m'arriver aussi, il y a de nombreuses années.la source
man
pagescp
sur BSD (au moins, OSX) et Gnucp
ne sont pas aussi explicites sur la "réécriture". Ce mot n'est utilisé que dans les commentaires sur les options-i
et-n
. La page de manuel Gnu est particulièrement peu informative, commençantCopy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.
La page deIn the first synopsis form, the cp utility copies the contents of the source_file to the target_file.
‘cp’ copies files (or, optionally, directories). The copy is completely independent of the original.
Je vois que la norme POSIX 2013 spécifie le comportement observé . Ça dit:
la source
cp
cela donnerait des résultats similairesmv
et casserait tous les liens durs dont le dest faisait partie. Mais maintenant que j'y pense, cela signifierait qu'il faudrait spécifiquementunlink(2)
la cible (cp -f
), ou créer un temporaire différemment nommé et ensuiterename(2)
. L'implémentation simple consiste à simplement ouvrir le fichier pour l'écraser, ce qui est requis par POSIX. Cela équivaut àcat src > dest
Si vous pouvez dire: «la copie d'un fichier vers le chemin de destination
paul
copie également le même fichier (même inode) vers tous les autres chemins de destination qui partagentpaul
l'inode»., Je suis désolé de dire que vous ne comprenez pas la notion de liens durs très bien. Si je donne une pomme à Sir McCartney, j'ai donné une pomme à Paul et j'ai donné une pomme au partenaire auteur-compositeur de John Lennon. Mais je n'ai pas distribué trois pommes; J'ai donné une pomme à une personne qui a plusieurs noms / titres / descripteurs.De même, lorsque vous copiez
george
verspaul
, vous ne le copiez pas égalementjohn
. Vous copiez plutôt lesgeorge
données dans le fichier dont l'inode est pointé par l'paul
entrée de répertoire.Étape par étape: quand vous le faites
vous avez créé un nouveau fichier (en supposant qu'il n'y avait pas déjà un fichier nommé
john
dans ce répertoire). Ou, pour parler plus strictement, cela suppose qu'il n'y avait pas déjà une entrée de répertoire avec le nomjohn
dans ce répertoire (car, à proprement parler, il n'y a pas de fichiers dans les répertoires; seulement des entrées de répertoire, qui pointent vers des inodes). Après avoir faitou
vous n'avez pas créé de nouveau fichier; vous avez plutôt donné un nouveau nom à votre fichier existant. Vous avez maintenant un fichier avec deux noms:
john
etpaul
. Et quand tu disvous écrasez ce fichier . Le fait qu'il porte deux noms est sans importance; elle pourrait avoir 42 noms, peut-être dans des endroits auxquels vous ne pouvez même pas accéder, et cette commande ne copierait pas les
george\n
données dans tous ces noms (chemins); il s'agit simplement de copier les données dans un seul fichier qui a plusieurs noms.la source
john
etpaul
commencez comme deux chemins pour le même fichier. Mais c'était la manière la plus simple à laquelle je pouvais penser pour m'exprimer. Je ne pense pas que la simple notion de lien dur, correctement comprise, dicte l'un ou l'autre des deux comportements pourcp
(sans-l
).