Linux - Nur neue und größere Dateien kopieren

3403
das Keks

Ich habe zwei Verzeichnisse mit Tausenden von Dateien, die mehr oder weniger dieselben Dateien enthalten.

Wie kann ich alle Dateien von dirA nach dirB kopieren, die nicht in dirB sind oder wenn die Datei in dirB vorhanden ist, diese nur überschreiben, wenn sie kleiner ist.

Ich weiß, dass es viele Beispiele für unterschiedliche Zeitstempel oder unterschiedliche Dateigrößen gibt. Ich möchte jedoch nur überschreiben, wenn die Zieldatei kleiner ist und unter keinen Umständen, wenn sie größer ist.

Hintergrund meines Problems:
Ich habe auf meinem Minecraft Server eine Dynmap gerendert, aber einige Kacheln fehlen oder sind beschädigt. Dann habe ich das Rendern erneut auf einem anderen Rechner mit einer schnelleren CPU durchgeführt und alle neuen gerenderten Dateien (~ 50 GB / 6.000.000 ~ 4-10 KB PNGs) auf meinen Server kopiert. Danach fiel mir auf, dass in meinem neuen Render auch beschädigte Dateien vorhanden sind.

links: altes Rendern, rechts: neues Rendern

alt 1 beschädigt neu 1

alt 2 neue 2 beschädigt

Daher möchte ich nicht alle Dateien überschreiben, sondern nur die Dateien, die größer sind (die beschädigten Dateien tragen weniger Daten und sind kleiner).

2
Verwenden Sie `cp` mit einer Kombination von` cmp'-Befehlen oder besser `rsync`, das alle gewünschten Optionen bietet Alex vor 7 Jahren 0
Welche Option muss ich mit rsync verwenden? Ich habe nichts für größere Dateien gefunden, nur neuere oder andere Größe. Darum habe ich gefragt. das Keks vor 7 Jahren 0
Verwenden Sie `stat` für Dateien an beiden Speicherorten, um die Dateigröße zu erhalten, und kopieren Sie sie, wenn sie Ihren Bedingungen dann entspricht Alex vor 7 Jahren 0
Nun, es war eine Herausforderung, suchte nach "rsync" -Optionen, die Sie brauchen, aber nicht die richtige finden, also ging es mit einem einfachen Weg Alex vor 7 Jahren 0

3 Antworten auf die Frage

2
Alex

Es mag ein schmutziger Weg sein, aber ich hoffe, es ist was Sie suchen

#!/bin/bash  ### Purpose: # Copy huge amount of files from source to destination directory only if # destination file is smaller in size than in source directory ###  src='./d1' # Source directory dst='./d2' # Destination directory  icp() { f="$"; [ -d "$f" ] && { [ ! -d "$$" ] && mkdir -p "$$"; return }  [ ! -f "$/$" ] && { cp -a "$" "$/$"; return; } fsizeSrc=$( stat -c %s "$f" ) fsizeDst=$( stat -c %s "$/$" ) [ $ -lt $ ] && cp -a "$" "$/$" }  export -f icp export src export dst  find $ -exec bash -c 'icp "$0"' {} \; 
Vielen Dank. Ich habe es mit einigen Testdaten getestet und funktioniert so, wie ich es brauche. Wenn ich es jedoch auf meinen realen Daten ausführen möchte, habe ich ein Problem, weil das Verzeichnis zu viele Dateien enthält (ungefähr 6.000.000): `ls Argumentliste zu lang`) das Keks vor 7 Jahren 0
Dies ist das Betriebssystemlimit (Sie können es für Ihr System als: "getconf ARG_MAX" erhalten). Sie haben wahrscheinlich ziemlich lange Dateinamen oder sehr tiefe Verzeichnisse. Wenn also `find` feed` ls` mit solchen Namen angegeben wird, überschreitet sie die maximal zulässige Länge für die Befehlszeile. Ich habe ein kleines Skript überarbeitet, um den Befehl 'ls' zu beseitigen. Könnten Sie diese neue Version ausprobieren? Alex vor 7 Jahren 0
Wenn das Skript erneut verschluckt, versuchen Sie möglicherweise, den gesamten Pfad zu reduzieren, indem Sie es in einen kurzen Pfad einbinden. Zum Beispiel `sudo mkdir -m 777 / a` dann das Quellverzeichnis an` / a` als `sudo mount --bind / pretty / long / prefix / an / source / directory / a` anhängen und dann` / a` in my verwenden Skript. Wenn Sie fertig sind, heben Sie die Bereitstellung von "/ a" mit dem folgenden Befehl auf: "sudo umount / a" Alex vor 7 Jahren 0
Ich denke, es ist nicht die Pfadlänge, da der längste Pfad (einschließlich Dateiname) etwa 80 Zeichen lang ist. Könnte es die Liste sein, die an die jeweils übergeben wird, die zu lang ist? Ich denke, diese Frage zielt auf etwas Ähnliches ab: http://unix.stackexchange.com/questions/128559/solving-mv-argument-list-too-long das Keks vor 7 Jahren 0
Möglicherweise ist 'diff --brief -r dir1 / dir2 / `ein guter Ansatz und führt dann für jede Zeile der Ausgabe etwas aus. Ich werde versuchen, so etwas am Abend zu konstruieren. das Keks vor 7 Jahren 0
@dasKeks Sie haben absolut Recht, dass die Liste der riesigen Dateien nicht in die Schleife passt. Ich habe das Skript komplett neu geschrieben, damit es nicht verschluckt wird Alex vor 7 Jahren 0
Was bedeutet die Option "-f"? Ich erhalte die Fehlermeldung `Export: Ungültige Option -f` das Keks vor 7 Jahren 0
Es ist eine "bash" -Option. Ändern Sie "#! / Bin / sh" in "# / bin / bash" wie im aktualisierten Skript Alex vor 7 Jahren 0
1
Pankaj Jackson

Sie können den Befehl rsync verwenden

Syntax :

-a = archive mode -v = increase verbosity -z = compress file data during the transfer --progress = show progress during transfer 

rsync -avz --progress <source path> <destination path>

Sie können verwenden --delete, um nicht benötigte Dateien aus dem Zielverzeichnis zu löschen

rsync -avz --delete --progress <source path> <destination path>

Ihr Befehl lautet also:

rsync -avz --delete --progress dirA dirB 
Kopiert das Flag -a nicht alle Dateien, die einen neueren Zeitstempel oder eine andere Dateigröße haben? Es ist wichtig, dass nur kleinere Dateien überschrieben werden. das Keks vor 7 Jahren 1
Dieser Befehl überschreibt nichts, es werden nur geänderte Dateien und neue Dateien kopiert, die unter Destination Director nicht verfügbar sind. Pankaj Jackson vor 7 Jahren 0
Geänderte Dateien werden im Ziel überschrieben. Unabhängig von der Größe der Zieldatei. Ich habe es mit einigen Daten getestet und die Option -a ist nicht das, was ich brauche. das Keks vor 7 Jahren 0
0
user32916

Mein Problem war ähnlich gewesen. Ich wollte Dateien von einem Remote-Ordner mit einem lokalen Ordner synchronisieren, aber nur die Remote-Dateien kopieren, die größer als die entsprechenden lokalen Dateien waren.

Mein Workaround mit Rsync war so, was eigentlich ein bash-Einzeiler ist:

for x in $(ls -1 home/me/local/folder/*) do eachsize=$(stat -c "%s") rsync -avz --progress --max-size=$ remote:/home/you/folder/$ . done 

Ich denke, Sie können den Punkt erhalten, da die Dateinamen zwischen den beiden Ordnern gleich sind. Ich gehe jeden im lokalen Ordner durch und halte seine Größe. Dann stelle ich als Begrenzung fest, ob Rsync die Remote-Datei kopieren soll oder nicht der gleiche Name, aber unterschiedliche Größe.

Verwenden Sie nicht `` ls`` so; mach einfach `` für x in home / me / local / folder / * ``. G-Man vor 6 Jahren 0
Du hast recht; nur um meinen Punkt zu sagen. user32916 vor 6 Jahren 0