So kopieren Sie ein Verzeichnis rekursiv mithilfe von Hardlinks für jede Datei

52

Ich möchte eine "Kopie" eines Verzeichnisbaums erstellen, in dem jede Datei einen Hardlink zur Originaldatei darstellt

Beispiel: Ich habe eine Verzeichnisstruktur:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3

Hier ist das erwartete Ergebnis, eine "Kopie" des Verzeichnisbaums, in der jede Datei einen Hardlink zur Originaldatei darstellt:

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
Gudmundur Orn
quelle

Antworten:

50

Unter Linux (genauer gesagt mit der GNU und den busyboxImplementierungen, cpdie normalerweise auf Systemen mit Linux als Kernel zu finden sind) und neuerem FreeBSD ist dies wie folgt:

cp -al dirA dirB

Eine portablere Lösung finden Sie unter Antwort mit pax und cpio von Stéphane Chazelas

Gudmundur Orn
quelle
Beachten Sie, dass Symlinks unter paxFreeBSD cp -anicht hart verlinkt werden.
Stéphane Chazelas
Beachten Sie, dass harte Links nicht über separate Dateisystem-Mounts funktionieren.
Dave
24

POSIXly würden Sie paxim Lese- + Schreibmodus mit der -lOption verwenden:

pax -rwlpe -s /A/B/ dirA .

( -peBewahrt alle möglichen Attribute von Dateien (in diesem Fall nur Verzeichnisse) , die kopiert werden, wie GNU cp‚s der -aFall ist).

Obwohl dies Standard ist , ist dieser Befehl nicht unbedingt sehr portabel .

Erstens enthalten viele GNU / Linux-basierte Systeme paxstandardmäßig keine (obwohl dies ein nicht optionales POSIX-Dienstprogramm ist).

Dann verursachen eine Reihe von Fehlern und Nichtkonformitäten mit einigen Implementierungen eine Reihe von Problemen mit diesem Code.

  • Aufgrund eines Fehlers paxfunktioniert Solaris 10 (zumindest) nicht, wenn es -rwlin Kombination mit verwendet wird -s. Aus irgendeinem Grund wird anscheinend der ursprüngliche und der kopierte Pfad ersetzt. Also würde es oben versuchen, einige zu tun, link("dirB/file", "dirB/file")anstatt link("dirA/file", "dirB/file").
  • Erstellt unter FreeBSD paxkeine Hardlinks für Dateien vom Typ symlink (ein von POSIX zugelassenes Verhalten). Darüber hinaus wird die Substitution auf die Ziele der Symlinks angewendet (ein von POSIX nicht zugelassenes Verhalten ). Wenn zum Beispiel ein foo -> AASymlink in vorhanden ist dirA, wird er foo -> BAin dirB.

Wenn Sie dasselbe tun möchten, jedoch mit beliebigen Dateipfaden, deren Inhalt in $srcund gespeichert ist $dst, ist es wichtig zu wissen , dass pax -rwl -- "$src" "$dst"die vollständige Verzeichnisstruktur von $srcinside erstellt wird $dst(das muss existieren und ein Verzeichnis sein). Zum Beispiel, wenn $srcist foo/bar, dann $dst/foo/barwird erstellt.

Wenn Sie stattdessen $dsteine Kopie von sein möchten , $srcist es wahrscheinlich am einfachsten, dies wie folgt zu tun:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && pax -rwlpe . "$absolute_dst")

( $dstDies würde auch die meisten der oben genannten Probleme umgehen , würde jedoch fehlschlagen, wenn der absolute Pfad von in Zeilenumbrüchen endet.)

Nun, das wird auf GNU / Linux-Systemen, auf denen es keine gibt, nicht helfen pax.

Interessanterweise paxwurde POSIX erstellt, um die Funktionen der Befehle tarund zusammenzuführen cpio.

cpioist ein historischer Unix-Befehl (von 1977) im Gegensatz zu einer POSIX-Erfindung, und es gibt auch eine GNU-Implementierung (keine eine pax). Obwohl es sich nicht mehr um einen Standardbefehl handelt (es war allerdings in SUSv2), ist er dennoch weit verbreitet, und es gibt eine Reihe grundlegender Funktionen, auf die Sie sich normalerweise verlassen können.

Das Äquivalent von pax -rwlwäre cpio -pl. Jedoch:

  1. cpio Verwendet die Liste der Eingabedateien in stdin im Gegensatz zu Argumenten (durch Zeilenumbrüche getrennt, dh Dateinamen mit Zeilenumbrüchen werden nicht unterstützt)
  2. Alle Dateien müssen angegeben werden (in der Regel geben Sie die Ausgabe von find( findund cpiowurden gemeinsam von denselben Personen entwickelt)).
  3. Metadaten werden nicht beibehalten (bei einigen cpioImplementierungen gibt es Optionen zum Beibehalten einiger, aber keine portierbaren).

Also mit cpio:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && find . | cpio -pl "$absolute_dst")
Stéphane Chazelas
quelle
Scheint, dass -s / A / B / für mein Beispiel spezifisch ist. Wie würden Sie dies tun, wenn der Name des Quellverzeichnisses und des Zielverzeichnisses die Variablen $ sourcedir und $ targetdir wären?
Gudmundur Orn
@GudmundurOrn, siehe bearbeiten.
Stéphane Chazelas
Ich führe diesen Befehl unter OS X aus und erhalte nur die Fehlermeldung "pax: Datei ./a.txt kann nicht mit sich selbst verknüpft werden". Ich habe den Befehl your wörtlich verwendet und nur das Quellverzeichnis durch den tatsächlichen Namen ersetzt, wobei ich / A / B und den letzten Punkt unverändert gelassen habe. Verstehe ich etwas falsch?
db
@db, -s /A/Bersetzt Adurch Bso das dirAwird dirB. Wenn der Name Ihres Quellverzeichnisses nein Alautet, wird er über sich selbst kopiert (verknüpft). Siehe auch den Rest der Antwort für möglicherweise bessere Ansätze.
Stéphane Chazelas
6

Kurze Antwort:

cd $source_folder
pax -rwlpe . $dest_folder
lkraider
quelle
2

Falls Sie nach dieser Funktion zum Kopieren mit Hardlinks suchen , um Snapshots oder Backups Ihrer Dateien (ganz oder teilweise) zu erstellen, sehen Sie sich diese an rsnapshot.

Janis
quelle
1
Das ist interessant. Ich denke aber, Hardlinks sind nur dann ein guter Schnappschuss-Mechanismus, wenn die Dateien nicht verändert werden. Richtig?
Gudmundur Orn
@Gudmundur Orn; Das ist richtig. Das in meiner Antwort erwähnte Tool erstellt einen neuen Schnappschuss in einer Weise, dass Dateien eindeutig sind. dh vorhandene (nicht geänderte) Dateien werden als Hardlinks erstellt und neue Dateien (oder geänderte Versionen vorhandener Dateien) werden als neue Dateien erstellt. Infolgedessen haben Sie die geringste Redundanz.
Janis
0

Die Antwort von @ gudmundur-orn ist richtig, aber wenn Sie auf BtrFS unter Linux sind, cp a --reflink=auto dirA dirBsollten Sie den Trick machen, mit dem Unterschied, dass die Dateien tatsächlich unterschiedlich sind und sich ändern, ändert sich nicht das eine. Mit cp -ceinem Mac mit APFS können Sie fast dasselbe erreichen ( autoführt eine vollständige Kopie durch, wenn dies nicht möglich ist, -cschlägt fehl).

Jedes COW-Dateisystem sollte dazu in der Lage sein, aber die Anbieter haben sich nicht auf eine Standard-Befehlszeilenoption geeinigt.

rbanffy
quelle