linux merge ordner: rsync?

13

Ich habe zwei Kopien eines Ordners

src/
dest/

Ich möchte sie folgendermaßen zusammenführen:

Wenn sich eine Datei nur in befindet src, möchte ich, dass sie in verschoben wirddest

Wenn eine Datei nur in ist dest, möchte ich, dass sie ignoriert wird und der IE in Ruhe gelassen wird.

Wenn sich eine Datei in beiden Ordnern befindet und identischen Inhalt hat (dh gleiche Größe und Datum), löschen Sie vonsrc

Wenn sich eine Datei in beiden Ordnern befindet und nicht den gleichen Inhalt hat, lassen Sie sie zurück, srcdamit ich sie manuell zusammenführen kann.

Nur eine sehr kleine Anzahl von Dateien (zwischen 0% und 5% der gesamten Dateien) sollte in dieser letzten Kategorie enthalten sein, aber ich weiß nicht, wie ich das in beiden und das gleiche von beiden trennen soll, aber unterschiedlich.

Ich habe versucht, herauszufinden, wie man das macht, rsyncaber bisher ohne Erfolg.

David Oneill
quelle

Antworten:

17

Ich habe nur eingeschränkte Funktionstests durchgeführt. Seien Sie also vorsichtig mit diesem Befehl (--dry-run):

rsync -avPr --ignore-existing --remove-source-files src/ dest

Bitte beachten Sie das nachfolgende /, da dies in src wiederkehrt, anstatt src selbst zu kopieren. Dies sollte Ihre vorhandenen Pfade beibehalten.

Wenn Sie das Flag --ignore-existing in Kombination mit dem Flag --remove-source-files verwenden, löschen Sie nur Dateien von src, die von src nach dest synchronisiert wurden, d. H. Dateien, die zuvor nicht nur in dest vorhanden waren.

Zum Löschen nicht synchronisierter Dateien, dh Dateien, die bereits in dest / wie in src / vorhanden waren, können Sie Folgendes verwenden:

for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done

oder

find src -type f -exec bash -c 'cmp -s "$0" "${0/#src/dest}" && rm "$0"' {} \;

Wenn Dateinamen Leerzeichen / neue Zeilen / ... enthalten könnten In Bezug auf Gilles 'Kommentar zu Sonderzeichen, ist dies sicherlich zu beachten, und es gibt viele Lösungen. Am einfachsten wäre es, ein -i an rm zu übergeben, was vor dem gesamten Löschen dazu führt. Vorausgesetzt, dass src / oder sein übergeordneter Pfad zum Auffinden bereitgestellt wird, sollte der vollständig qualifizierte Pfad jedoch dazu führen, dass alle Dateinamen von den Befehlen diff und rm ohne Anführungszeichen ordnungsgemäß behandelt werden.

Tok
quelle
korrektur: dieser befehl entfernt keine dateien von src, wenn in dest bereits eine identische kopie existiert
Tok
Ja :(. Das ist der Teil, den ich schwer herauszufinden
finde
2
Nun, die gute Nachricht ist, dass Sie es unabhängig und ohne großen Aufwand lösen können: for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done(Sie können das überspringen, || echo $filewenn Sie möchten, es ist der Vollständigkeit
halber
Nifty: das habe ich gebraucht. Bearbeiten Sie das in Ihre Antwort, und ich werde es akzeptieren!
David Oneill
@Tok: Ihr Befehl unterbricht Dateinamen, die Sonderzeichen enthalten (Leerzeichen,, \?*[Initiale -). Sie müssen Variablenersetzungen in doppelte Anführungszeichen setzen , --vor Dateinamen an Dienstprogramme übergeben und find … -exec …die Ausgabe von verwenden, anstatt sie zu analysieren find. Mit einem rmBefehl in der Mischung ist dies ein Rezept für eine Katastrophe.
Gilles 'SO- hör auf böse zu sein'
6

unison ist das Werkzeug, das Sie suchen. Versuchen Sie unison-gtk, wenn Sie eine GUI bevorzugen. Ich glaube aber nicht, dass ähnliche Dateien gelöscht werden. Versuchen Sie, beide Verzeichnisse identisch zu halten. Trotzdem wird es leicht 1) identifizieren, welche Dateien kopiert werden sollen; 2) welche müssen manuell zusammengeführt werden.

simonp
quelle
Es macht nicht genau das, was das OP verlangt, aber es hört sich so an, als würde es das ultimative Ziel des OP erreichen. +1
Ryan C. Thompson
+1 Leider ist auf dem Server, auf dem ich dies ausführe, weder unisono installiert, noch habe ich die Berechtigung, es zu installieren. Aber dies könnte eine gute Antwort auf eine andere Person sein.
David Oneill
1
Sie können die ausführbare Datei von seas.upenn.edu/~bcpierce/unison//download/… herunterladen . Installieren Sie es irgendwo in Ihrem Home-Verzeichnis, es ist nur eine Datei.
JooMing
2

Das folgende Skript sollte die Dinge vernünftig machen. Es verschiebt Dateien von der Quelle zum Ziel, überschreibt niemals eine Datei und erstellt bei Bedarf Verzeichnisse. Quelldateien, deren Ziel eine andere Datei ist, werden ebenso wie Dateien, die keine regulären Dateien oder Verzeichnisse sind (z. B. symbolische Links), alleine gelassen. Die in der Quelle verbleibenden Dateien sind diejenigen, für die ein Konflikt vorliegt. Vorsicht, ich habe es überhaupt nicht getestet.

cd src
find . -exec sh -c '
    set -- "/path/to/dest/$0"
    if [ -d "$0" ]; then #  the source is a directory 
      if ! [ -e "$1" ]; then
        mv -- "$0" "$1"  # move whole directory in one go
      fi
    elif ! [ -e "$0" ]; then  # the source doesn't exist after all
      :  # might happen if a whole directory was moved
    elif ! [ -e "$1" ]; then  # the destination doesn't exist
      mv -- "$0" "$1"
    elif [ -f "$1" ] && cmp -s -- "$0" "$1"; then  # identical files
      rm -- "$0"
    fi
  ' {} \;

Ein anderer Ansatz wäre, ein Union-Mount- Verzeichnis übereinander durchzuführen , beispielsweise mit funionfs oder unionfs-fuse .

Gilles 'SO - hör auf böse zu sein'
quelle