rsync --delete mit übergeordnetem Zielordner

rsync --delete mit übergeordnetem Zielordner

Ich habe einen rsyncProzess, der Inhalte aus einem Quell-Repository (das einer Versionskontrolle unterliegt) in ein gemeinsam genutztes NFS-Mount synchronisiert.

Das Szenario (so schlimm es auch ist) ist, dass der Zielordner mehr Inhalt enthält als der Quellordner, weil andere Inhalte aus anderen Quellen mit dem Zielordner synchronisiert werden. Ordnerstrukturen können beispielsweise so aussehen:

Quelle

a/a1.txt
a/a2.txt
b/b1.txt

Ziel

a/a1.txt
a/a2.txt
a/a3.txt
b/b1.txt
c/c1.txt

(in diesem Beispiel a/a3.txtund c/c1.txtwerden von woanders mit dem Ziel synchronisiert. In der Praxis handelt es sich dabei um mehrere andere Quellen und die Inhalte/Prozesse für diese können nicht beeinflusst werden.)

Nehmen wir nun an, dass der Quellordner die a/a2.txtDatei löscht. Mit dem vorhandenen Setup würde diese Datei im Ziel nicht gelöscht werden. Die Verwendung von --deletewürde jedoch dazu führen, dass andere Dateien gelöscht werden, und dies darf nicht geschehen.

Wie kann --deleteich rsync verwenden und trotzdem die Anforderungen erfüllen? Da das Quellverzeichnis einer Versionskontrolle unterliegt, ist es ganz einfach, ein Vorher-Nachher-Bild dieses Verzeichnisses zu erhalten. So könnte ein differenzielles Backup unter Verwendung des ursprünglichen Quellverzeichnisses als Referenz berechnet werden. Aber ist das die beste Methode?

Antwort1

So können Sie es nicht verwenden rsync --delete. Es ist zustandslos und speichert keine Aufzeichnungen darüber, welche Dateien zwischen den Durchläufen gelöscht wurden. Das --deleteFlag weist lediglich an, rsyncalle Dateien am Ziel zu löschen, die in der Quelle nicht vorhanden sind.

Um diese eingeschränkte Löschung zu implementieren, müssen Sie meines Erachtens Ihren eigenen Status beibehalten. Weder rsyncnoch unisonkönnen dies für Sie tun.

Das Folgende ist keine vollständig fehlersichere Lösung; es ist ein Ausgangspunkt. (Es verarbeitet jedoch Dateien mit seltsamen Namen – einschließlich solcher, die eine eingebettete neue Zeile enthalten.)

Nehmen wir zwei Verzeichnisse srcund an dst. (Für die Zwecke des Beispiels spielt es keine Rolle, ob dstlokal oder remote.)

# Find the current list of files (do this just once, to prep the cache)
( cd src && find . -type f -print0 ) | LC_ALL=C sort -z > .state.src

Führen Sie bei jeder Sicherung den folgenden Code aus

# Run the rsync to transfer files. "dst/" could be local
rsync -av src/ remote:dst/

# Determine the set of files to delete in "dst/"
( cd src && find . -type f -print0 ) | LC_ALL=C sort -z | tee .state.src.new |
    LC_ALL=C comm -z - -13 .state.src |
    ssh remote 'while IFS= read -d "" -r f; do rm -f "dst/$f"; done'

# That seemed to work, so update the state cache
[[ 0 -eq $? ]] && mv -f .state.src.new .state.src

Wenn Ihre Version comm(wie meine) älter als GNU Coreutils 8.25 ist und das Flag nicht hat -z, können Sie diesen alternativen Workaround verwenden:

# Find the current list of files (do this just once, to prep the cache)
( cd src && find . -type f -print0 ) | tr '\0\n' '\n\0' | LC_ALL=C sort > .state.src

Führen Sie bei jeder Sicherung den folgenden Code aus

# Run the rsync to transfer files. "dst/" could be local
rsync -av src/ remote:dst/

# Determine the set of files to delete in "dst/"
( cd src && find . -type f  -print0 ) | tr '\0\n' '\n\0' | LC_ALL=C sort | tee .state.src.new |
    LC_ALL=C comm -13 - .state.src |
    tr '\0\n' '\n\0' |
    ssh remote 'while IFS= read -d "" -r f; do rm -f "dst/$f"; done'

# That seemed to work, so update the state cache
[[ 0 -eq $? ]] && mv -f .state.src.new .state.src

verwandte Informationen