Jak porównać dwa foldery i skopiować różnicę do trzeciego folderu?

23

Masz trzy foldery:

  • folder bieżący , który zawiera bieżące pliki
  • folder stary , który zawiera starszą wersję tych samych plików
  • różnica folderów , która jest tylko pustym folderem

Jak porównać stare z bieżącym i skopiować pliki, które są inne (lub całkowicie nowe) w bieżącym, aby je odróżnić ?


Szukałem dookoła i wydaje się, że jest to prosta sprawa, ale nie mogę sprawić, by działała w moim konkretnym przykładzie. Większość źródeł sugerowała użycie rsync, więc skończyłem z następującą komendą:

rsync -ac --compare-dest=../old/ new/ difference/

Powoduje to jednak kopiowanie wszystkich plików z nowego na różnicowy , nawet tych, które są takie same jak w starych .

W przypadku, gdy to pomaga (może polecenie jest w porządku, a wina leży gdzie indziej), oto jak to przetestowałem:

  1. Zrobiłem trzy foldery.
  2. Zrobiłem kilka starych plików tekstowych o różnych treściach .
  3. Skopiowałem pliki ze starego na nowy .
  4. Zmieniłem zawartość niektórych plików w nowym i dodałem kilka dodatkowych plików.
  5. Uruchomiłem powyższe polecenie i sprawdziłem różnice w wynikach .

W ciągu ostatnich kilku dni szukałem rozwiązania i naprawdę doceniłbym pomoc. Nie musi to koniecznie używać rsync, ale chciałbym wiedzieć, co robię źle, jeśli to możliwe.

Szlachcic angielski
źródło
możliwy duplikat Jak zapisać zmienione pliki?
wingedsubmariner
@wingedsubmariner Nie sądzę, że jest to duplikat, ponieważ zaakceptowana odpowiedź na połączone pytanie jest poleceniem, o które OP zadaje pytanie.
Bernhard
@Bernhard Ah, mój zły. Chyba źle zrozumiałem pierwotne pytanie.
wingedsubmariner
@wingedsubmariner Nie martw się, powiedziałeś „możliwe” i zgadzam się, że wygląda bardzo podobnie :)
Bernhard

Odpowiedzi:

7

Nie jestem pewien, czy możesz to zrobić za pomocą istniejących poleceń Linux, takich jak rsync lub diff. Ale w moim przypadku musiałem napisać własny skrypt za pomocą Pythona, ponieważ Python ma moduł „filecmp” do porównywania plików. Cały skrypt i użycie zamieściłem na mojej osobistej stronie - http://linuxfreelancer.com/

Jego użycie jest proste - podaj bezwzględną ścieżkę nowego katalogu, starego katalogu i katalogu różnic w tej kolejności.

#!/usr/bin/env python

import os, sys
import filecmp
import re
from distutils import dir_util
import shutil
holderlist=[]

def compareme(dir1, dir2):
    dircomp=filecmp.dircmp(dir1,dir2)
    only_in_one=dircomp.left_only
    diff_in_one=dircomp.diff_files
    dirpath=os.path.abspath(dir1)
    [holderlist.append(os.path.abspath( os.path.join(dir1,x) )) for x in only_in_one]
    [holderlist.append(os.path.abspath( os.path.join(dir1,x) )) for x in diff_in_one]
    if len(dircomp.common_dirs) > 0:
        for item in dircomp.common_dirs:
            compareme(os.path.abspath(os.path.join(dir1,item)), os.path.abspath(os.path.join(dir2,item)))
        return holderlist

def main():
 if len(sys.argv) > 3:
   dir1=sys.argv[1]
   dir2=sys.argv[2]
   dir3=sys.argv[3]
 else:
   print "Usage: ", sys.argv[0], "currentdir olddir difference"
   sys.exit(1)

 if not dir3.endswith('/'): dir3=dir3+'/'

 source_files=compareme(dir1,dir2)
 dir1=os.path.abspath(dir1)
 dir3=os.path.abspath(dir3)
 destination_files=[]
 new_dirs_create=[]
 for item in source_files:
   destination_files.append(re.sub(dir1, dir3, item) )
 for item in destination_files:
  new_dirs_create.append(os.path.split(item)[0])
 for mydir in set(new_dirs_create):
   if not os.path.exists(mydir): os.makedirs(mydir)
#copy pair
 copy_pair=zip(source_files,destination_files)
 for item in copy_pair:
   if os.path.isfile(item[0]):
    shutil.copyfile(item[0], item[1])

if __name__ == '__main__':
 main()
Daniel t.
źródło
21

Zorientowałem się, na czym polega problem w moim przypadku:

Porównywane przeze mnie pliki miały różne znaczniki czasu. Zakładam, że nie powinienem był używać argumentu -a , ponieważ rsync starał się zachować znaczniki czasu podczas kopiowania plików. Polecenie, które działało dla mnie było:

rsync -rvcm --compare-dest=../old/ new/ difference/
Szlachcic angielski
źródło
Myślę, że aby przetestować to z opcją -a (archiwum), powinieneś był użyć rsync -a„kopiować” pliki początkowo (lub odpowiednik cp), a następnie usunąć lub zmodyfikować. (Lubię trzymać się rsync, ponieważ wiem, że jest samowystarczalny, nie myśląc o tym, co może robić). Myślę, że powinno to działać z oryginalnym poleceniem. Opcja -a obejmuje -t (porównaj według znacznika czasu), który jest alternatywą dla -c (porównaj według sumy kontrolnej).
mędrzec
2
Moim zdaniem ta odpowiedź powinna być jedną z zaakceptowanych, ponieważ jest o wiele prostsza. Również polecenie działało dla mnie tylko wtedy, gdy podałem pełną ścieżkę do old/i new/.
Yamaneko
Zastrzeżenie wydaje się polegać na tym, że porównywarka-dest musi być względną ścieżką do różnicy widzianej z wnętrza faktycznego przeznaczenia
Ryan Williams
1

Może to pomóc niektórym czytelnikom: W systemie Windows starszy, mały darmowy program - Third Dir - robi dokładnie to, o co tu proszono. Nie jest już dostępny za pośrednictwem dewelopera Roberta Vašíčka. Ale jestem pewien, że można go znaleźć w niektórych repozytoriach online.

Oto opis programisty, który pozostaje na jego stronie:

Trzeci katalog: niezwykły synchronizator katalogów - różne pliki są kopiowane do trzeciego katalogu. Bardzo przydatne jest wyodrębnienie np. Nowych lub edytowanych zdjęć z dużego drzewa katalogów na dysku stałym do folderu tymczasowego, a następnie dodanie ich do archiwum CD (uwaga - oryginalne pliki są porównywane z CD). Wersja 1.4, rozmiar 23kB. Utworzono 2005-02-12.

Historia: Wersja 1.14 - Bardziej wydajna, gdy porównywane jest wiele dziesiątek tysięcy plików.

Steve
źródło
0

Sposób rsync podany przez Thane'a z dodatkami Yamaneko działa świetnie, ale pozostawia puste katalogi. Dla mnie ostateczne rozwiązanie było w dwóch krokach: najpierw wywołaj rsync z pełną ścieżką, a następnie polecenie find, aby usunąć wszystkie puste katalogi:

rsync -rvcm --compare-dest=/tmp/org/ /tmp/new/ /tmp/difference/
find /tmp/difference/ -d -type d -empty -exec rmdir {} \; -print

Pamiętaj, że nawet przy opcji --links rsync nie zachował dowiązań symbolicznych, ale skopiował dane docelowe.

PierreL
źródło
Zauważ, że zamiast -empty -exec rmdir {} \;ciebie możesz użyć -empty -delete.
mivk
-3

Używam dwupanelowego XY Explorera (komercyjnego), który potrafi robić wiele sztuczek i jest to jedna z nich. Otwórz Currentw jednym okienku, a Stary w drugim. Aktywuj bieżący panel. Przejdź do Panes > Sync Select. Daje 5 opcji do wyboru:

  1. Mecze (wymienione w obu)
  2. Unikalne (w aktywnym okienku)
  3. Nowsze (w aktywnym okienku)
  4. Unikalne i nowsze pliki (w aktywnym okienku)
  5. Wybrane (wybrane w drugim panelu)

Teraz możesz skopiować wynikowy wybór z Currentdowolnego miejsca. Użyłem go do porównania mailfoldersstarych instalacji z najnowszymi. Struktura folderów była dość złożona, ale (prawie) wszystkie mbs-filesmiały unikalny numer.

Przeprowadziłem więc wyszukiwanie mbs-filesw starym katalogu głównym mailfolder(w jednym okienku), a także w najnowszym (w drugim okienku) i porównałem wyniki wyszukiwania w każdym okienku ( Sync Select Unique) , aby znaleźć wiadomości, które zaginęły podczas ponownie instaluje)! Możesz także ustawić wiele opcji.

Martijn Douwes
źródło
1
Jeśli mówisz o niestandardowym oprogramowaniu, powinieneś dołączyć link. Jeśli masz na myśli XYplorer, który wcale nie pomoże OP.
Anthon