rsync eine Liste von Verzeichnissen mit absolutem Pfad in der Textdatei

8

Ich habe eine Textdatei mit einer Liste von Verzeichnissen mit ihrem absoluten Pfad

$ cat DirectoriesToCopy.txt

/data/Dir1
/data/Dir2

Ich möchte rsync verwenden, um alle diese Verzeichnisse zu kopieren und dabei den absoluten Pfad zu einem anderen Speicherort beizubehalten.

Ich habe den folgenden Befehl rsync ausprobiert, aber er funktioniert nicht

rsync -avr --include-from=DirectoriesToCopy.txt --exclude='*/' --exclude='/*'  /  /media/MyDestination/

Was läuft hier falsch?

Indiajoe
quelle
Wollen Sie übertragen /data/Dir1und /data/Dir2einschließlich ihres Inhalts /media/MyDestination/Dir1und /media/MyDestination/Dir2? Oder möchten Sie das /dataTeil einschließen ? Wie groß ist diese Liste, ist sie zu groß, um diese Einträge einfach in der Befehlszeile aufzulisten? Wie auch immer, Ihre --excludeAussagen verhindern die Rekursion.
Wurtel
Ich möchte auch alle Dateien in diesen Verzeichnissen übertragen. Es gibt viele Dateien in diesem Verzeichnis, daher möchte ich vermeiden, eine andere Textdatei mit allen Dateinamen zu erstellen.
Indiajoe
Ich möchte meinen vollen Weg gerne behalten /media/MyDestination/data/Dir2/. Ich habe --exclude hinzugefügt, um zu verhindern, dass andere Verzeichnisse und Dateien in / kopiert werden.
Indiajoe
In Fällen, in denen die Liste der Verzeichnisse nicht sehr groß ist, ist die folgende Option rsync -av $(cat DirectotiesToCopy.txt) /media/MyDestination/
wahrscheinlich

Antworten:

6

Verwenden Sie den folgenden Befehl:

rsync -av --include-from=DirectoriesToCopy.txt --include /data/ --exclude='/data/*' --exclude='/*/' / /media/MyDestination/

Sie müssen / data / explizit einfügen, das hätten Sie auch der Liste in der Datei hinzufügen können. Schließen Sie dann alle anderen Verzeichnisse aus (die Reihenfolge ist bei Einschlüssen / Ausschlüssen wichtig).

Beachten Sie, dass Ihre Verwendung von -rredundant war, da dies in enthalten ist -a.

EDIT: Sie können das gleiche Ergebnis auch erzielen mit:

rsync -av --relative /data/Dir1 /data/Dir2 /media/MyDestination/

Es ist nicht rsync, das Sie dazu zwingt, schwierige Dinge zu tun, nur um ein paar Verzeichnisse zu kopieren. Es gibt Ihnen nur mehrere Möglichkeiten, dasselbe zu tun. In einigen Fällen ist es möglicherweise besser, den Einschluss- / Ausschluss-Weg zu wählen. Hier würde ich das - Relative oben tun (ohne dass --relativeSie mit /media/MyDestination/Dir1und enden würden /media/MyDestination/Dir2, wobei --relativeder gesamte Quellpfad zum Ziel kopiert wird).

wurtel
quelle
Danke, dass es funktioniert hat. Ich bin ein wenig überrascht, dass man eine so sorgfältige Reihenfolge von Filtern definieren muss, um einfach eine Liste von Verzeichnissen mit rsync zu kopieren. Wenn sich meine Verzeichnisliste beispielsweise nicht unter einem gemeinsamen Verzeichnis / data / befand, sondern auf viele Speicherorte verteilt war, werden die zu definierenden Filter ziemlich kompliziert.
Indiajoe
Siehe meine Bearbeitung meiner Antwort.
Wurtel
Vielen Dank. Wenn meine Liste der Verzeichnisse nicht sehr groß ist, kann ich das Flag --relative wie unten gezeigt verwenden. rsync -av --relative $(cat DirectotiesToCopy.txt) /media/MyDestination/
Indiajoe
Ja; Denken Sie daran, --relativeist nur eine weitere Option.
Wurtel
7

Ich möchte rsync verwenden, um alle diese Verzeichnisse [aus einer Liste] zu kopieren und dabei ihren absoluten Pfad zu einem anderen Speicherort beizubehalten

Verwenden Sie keine Variationen --includeoder --filterVariationen, da dies die Dinge nur verwirrt. Verwenden Sie stattdessen --files-from=_filename_. (Wenn Sie dies tun, stellen Sie sicher, dass Sie viele Tests durchführen.)

  1. Erstellen Sie die Verzeichnisliste in einer Datei, einem Verzeichnis / einer Datei pro Zeile.

  2. Verwenden Sie rsync's --files-from=mit der obigen Datei.

  3. Verwenden Sie die Option --relative/ -R, um sicherzustellen, dass die Quellpfadnamen am Ende des Ziels kopiert werden.

  4. Auch wenn Sie die -aOption haben, schließen Sie auch ein -r. Von der Manpage:

    In beiden Fällen würde, wenn die Option -r aktiviert wäre, auch die gesamte Hierarchie dieses Verzeichnisses übertragen (beachten Sie, dass -r explizit mit --files-from angegeben werden muss, da dies nicht durch -a impliziert wird).

Vollständiger Befehl:

rsync ${DEBUG:+-nv} -arR --files-from=<list_of_files.txt> <top-level-dir>  <target-dir>

(Die Dateien in list_of_files.txt müssen relativ sein oder sich im Verzeichnis der obersten Ebene befinden. )

(Wenn DEBUG gesetzt ist, druckt rsync lediglich aus, was möglicherweise kopiert wurde.)

Otheus
quelle
1
Das habe ich gebraucht! "--Include-from" sollte jedoch "--files-from" sein. Außerdem habe ich "--list-only" verwendet, um eine Vorschau der Funktionen von RSYNC anzuzeigen, bevor es tatsächlich funktioniert.
Adambean
1
Danke, ich habe die Antwort aktualisiert. --include-fromwird auch funktionieren, aber was ich dann gesagt habe, -rist weitgehend irrelevant.
Otheus
2

Das rsync-Handbuch warnt vor diesem Szenario (Abschnitt „Musterregeln ein- / ausschließen“):

das wird nicht funktionieren:

+ /some/path/this-file-will-not-be-found
+ /file-is-included
- *

Dies schlägt fehl, da das übergeordnete Verzeichnis "some"von der '*'Regel ausgeschlossen wird , sodass rsync niemals eine der Dateien in den Verzeichnissen "some"oder besucht "some/path". Eine Lösung besteht darin, zu verlangen, dass alle Verzeichnisse in der Hierarchie mit einer einzigen Regel aufgenommen werden: "+ */"(irgendwo vor die "- *"Regel stellen), und möglicherweise die --prune-empty-dirsOption zu verwenden. Eine andere Lösung besteht darin, spezifische Einschlussregeln für alle übergeordneten Verzeichnisse hinzuzufügen, die besucht werden müssen. Zum Beispiel funktioniert dieses Regelwerk einwandfrei:

+ /some/
+ /some/path/
+ /some/path/this-file-is-found
+ /file-also-included
- *

In Ihrem Fall, ich denke , die einfachste Ansatz , um die Liste der Verzeichnisse zu vorverarbeiten wäre so zu schließen , dass , wann immer Sie sind /path/to/foo, Sie sind auch alle übergeordneten Verzeichnisse ( /path/to, /path, /) und auch Verzeichnisse der ursprünglichen Verzeichnisse enthalten ( /path/to/foo/***) und nach All dies hat eine Regel, die alles ausschließt, was zuvor nicht aufgeführt war ( *).

<DirectoriesToCopy.txt awk '
    {print "+ " $0 "/***"; while (sub(/\/+[^\/]+\/*$/, "/")) print "+ " $0}
    END {print "- *"}
' >rsync-rules.txt
rsync -avr --include-from=rsync-rules.txt  /  /media/MyDestination/
Gilles 'SO - hör auf böse zu sein'
quelle
Vielen Dank für die ausführliche Erklärung und das Skript zum Erstellen der Regeldatei. Ich verstehe das Problem jetzt. Ich finde es immer noch schön, wenn rsync eine Option wie --dirs-from = DirectoriesToCopy.txt als Abkürzung für alle komplizierten Filter hätte.
Indiajoe