Je veux créer une "copie" d'une arborescence de répertoires où chaque fichier est un lien dur vers le fichier d'origine
Exemple: j'ai une structure de répertoires:
dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3
Voici le résultat attendu, une "copie" de l'arborescence des répertoires où chaque fichier est un lien dur vers le fichier d'origine:
dirB/ # normal directory
dirB/file1 # hardlink to dirA/file1
dirB/x/ # normal directory
dirB/x/file2 # hardlink to dirA/x/file2
dirB/y/ # normal directory
dirB/y/file3 # hardlink to dirA/y/file3
Sous Linux (plus précisément avec les implémentations GNU et busybox
de cp
que l'on trouve généralement sur les systèmes qui ont Linux comme noyau) et FreeBSD récent, c'est Comment:
cp -al dirA dirB
Pour une solution plus portable, voir la réponse en utilisant pax et cpio par Stéphane Chazelas
POSIXly, vous utiliseriez pax
en mode lecture + écriture avec l'option -l
:
pax -rwlpe -s /A/B/ dirA .
(-pe
Conserve tous les attributs possibles des fichiers (dans ce cas uniquement les répertoires) qui sont copiés, comme GNU cp
's -a
Le fait)).
Maintenant, bien que standard, cette commande n'est pas nécessairement très portable.
Tout d'abord, de nombreux systèmes basés sur GNU/Linux n'incluent pas pax
par défaut (même s'il s'agit d'un utilitaire POSIX non facultatif).
Ensuite, un certain nombre de bogues et de non-conformités avec quelques implémentations provoquent un certain nombre de problèmes avec ce code.
pax
(au moins) ne fonctionne pas lorsque vous utilisez -rwl
en combinaison avec -s
. Pour une raison quelconque, il semble qu'il applique la substitution à la fois au chemin d'origine et au chemin copié. Donc ci-dessus, il essaierait de faire de la link("dirB/file", "dirB/file")
au lieu de link("dirA/file", "dirB/file")
.pax
ne crée pas de liens physiques pour les fichiers de type symlink (un comportement autorisé par POSIX). Non seulement cela, mais il applique également la substitution aux cibles des liens symboliques (un comportement pas autorisé par POSIX). Par exemple, s'il existe un lien symbolique foo -> AA
Dans dirA
, il deviendra foo -> BA
Dans dirB
.De plus, si vous voulez faire de même mais avec des chemins de fichiers arbitraires dont le contenu est stocké dans $src
Et $dst
, Il est important de réaliser que pax -rwl -- "$src" "$dst"
Crée la structure de répertoire complète de $src
À l'intérieur de $dst
(Qui doit exister et être un répertoire). Par exemple, si $src
Est foo/bar
, Alors $dst/foo/bar
Est créé.
Si à la place, vous voulez que $dst
Soit une copie de $src
, Le plus simple est probablement de le faire comme:
absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && pax -rwlpe . "$absolute_dst")
(qui contournerait également la plupart des problèmes mentionnés ci-dessus mais échouerait si le chemin absolu de $dst
se termine par des caractères de nouvelle ligne).
Maintenant, cela n'aidera pas sur les systèmes GNU/Linux où il n'y a pas de pax
.
Il est intéressant de noter que pax
a été créé par POSIX pour fusionner les fonctionnalités des commandes tar
et cpio
.
cpio
est une commande historique Unix (de 1977) par opposition à une invention POSIX, et il y a également une implémentation GNU (pas un pax
one). Donc même si ce n'est plus une commande standard (elle était en SUSv2 cependant), elle est toujours très courante, et il existe un ensemble de fonctionnalités de base sur lesquelles vous pouvez généralement compter. sur.
L'équivalent de pax -rwl
Serait cpio -pl
. Toutefois:
cpio
prend la liste des fichiers d'entrée sur stdin par opposition aux arguments (délimité par des retours à la ligne, ce qui signifie que les noms de fichiers avec des caractères de nouvelle ligne ne sont pas pris en charge)find
(find
et cpio
ont été développés conjointement par les mêmes personnes)).cpio
ont des options pour en conserver, mais rien de portable).Donc avec cpio
:
absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && find . | cpio -pl "$absolute_dst")
Réponse courte:
cd $source_folder
pax -rwlpe . $dest_folder
Dans le cas où vous recherchez cette fonctionnalité copie avec liens durs pour créer des instantanés pour les sauvegardes de (tout ou partie de) vos fichiers, consultez rsnapshot
.
La réponse de @ gudmundur-orn est correcte, mais si vous êtes sur BtrFS sous Linux cp a --reflink=auto dirA dirB
devrait faire l'affaire, à la différence près que les fichiers sont réellement différents et changer l'un ne change pas l'autre. Vous pouvez obtenir la même chose avec cp -c
sur un Mac avec APFS (auto
fera une copie complète si ce n'est pas possible, -c
échouera).
Tout système de fichiers COW devrait être en mesure de le faire, mais les fournisseurs ne se sont pas mis d'accord sur une option de ligne de commande standard.