Chciałbym skopiować zestaw plików z katalogu A do katalogu B, z zastrzeżeniem, że jeśli plik w katalogu A jest identyczny z plikiem w katalogu B, plik ten nie powinien być kopiowany (a zatem jego czas modyfikacji nie powinien być zaktualizowane). Czy można to zrobić za pomocą istniejących narzędzi, bez pisania własnego skryptu?
Aby nieco rozwinąć mój przypadek użycia: automatycznie generuję kilka .c
plików w katalogu tymczasowym (metodą, która musi bezwarunkowo wygenerować je wszystkie), a kiedy je ponownie generuję, chciałbym tylko skopiować te, które zmieniły się w rzeczywisty katalog źródłowy, pozostawiając te niezmienione bez zmian (ze starymi czasami tworzenia), aby make
wiedzieć, że nie trzeba ich ponownie kompilować. ( .c
Jednak nie wszystkie generowane pliki są plikami, więc muszę porównywać binarnie, a nie porównywać tekst).
(Uwaga: wynikało to z pytania, które zadałem na https://stackoverflow.com/questions/8981552/speeding-up-file-comparions-with-cmp-on-cygwin/8981762#8981762 , gdzie próbowałem aby przyspieszyć plik skryptu, którego używałem do wykonania tej operacji, ale przychodzi mi do głowy, że naprawdę powinienem zapytać, czy istnieje lepszy sposób na zrobienie tego niż pisanie własnego skryptu - zwłaszcza, że jakikolwiek prosty sposób to zrobić w powłoce skrypt wywoła coś podobnego cmp
do każdej pary plików, a uruchomienie wszystkich tych procesów trwa zbyt długo).
źródło
diff -qr dirA dirB
aby zobaczyć, które pliki są unikatowedirA
idirB
, odpowiednio.rsync -avnc
lub dalekorsync --archive --verbose --dry-run --checksum
.Odpowiedzi:
rsync jest prawdopodobnie najlepszym narzędziem do tego. Polecenie zawiera wiele opcji, więc przeczytaj stronę podręcznika . Myślę, że chcesz opcję --checksum lub --ignore-times
źródło
-t
podano opcję) lub czas synchronizacji (jeśli-t
nie jest określony).rsync
nie. Jeśli to zrobię :,mkdir src dest; echo a>src/a; rsync -c src/* dest; sleep 5; touch src/a; rsync -c src/* dest
tostat dest/a
pokazuje, że mtime i ctime są o 5 sekund starsze niż tesrc/a
.--checksum
opcja i chociaż linux.die.net/man/1/rsync nie zawiera absolutnie nic , co sugerowałoby, że ma on wpływ na to, czy data modyfikacji jest aktualizowana, powoduje jednak pozostawienie daty modyfikacji miejsca docelowego nietknięty. (Z drugiej strony--ignore-times
opcja nie ma tego efektu; wraz z nią data modyfikacji jest wciąż aktualizowana). Biorąc pod uwagę, że wydaje się to całkowicie nieudokumentowane, czy mogę na tym polegać?rsync
przepływ pracy jest następujący: 1) sprawdź, czy plik wymaga aktualizacji; 2) jeśli tak, zaktualizuj plik.--checksum
Opcja powiedzieć, że nie powinny być aktualizowane, więcrsync
nie powinien przejść do kroku 2).--ignore-times
bez--checksum
kopiowałby każdy plik, a więc także aktualizował znacznik czasu, nawet jeśli pliki są identyczne.Możesz użyć
-u
przełącznika, abycp
:Ze strony podręcznika:
źródło
-u
robi flaga i jak ona działa oraz w jaki sposób pomogłoby to PO. Jednak w tym konkretnym przypadku nie pomogłoby to PO, ponieważ kopiowałoby identyczne pliki, gdyby były nowsze, i dlatego zmieniał ich znaczniki czasu, czego dokładnie chce OP.Chociaż używanie
rsync --checksum
to dobry ogólny sposób na „skopiowanie, jeśli zmieniono”, w twoim przypadku istnieje jeszcze lepsze rozwiązanie!Jeśli chcesz uniknąć niepotrzebnej ponownej kompilacji plików, powinieneś użyć ccache, który został zbudowany właśnie w tym celu! W rzeczywistości nie tylko pozwoli uniknąć niepotrzebnych
make clean
ponownych kompilacji automatycznie generowanych plików, ale także przyspieszy wszystko, gdy to zrobisz, i ponownie skompiluje od zera.Następnie jestem pewien, że zapytasz: „Czy to jest bezpieczne?” Tak, jak wskazuje strona internetowa:
I łatwo go użyć , po prostu dodając go jako przedrostek w
CC=
linii twojego makefile (lub możesz użyć dowiązań symbolicznych, ale sposób makefile jest prawdopodobnie lepszy).źródło
ccache file.c -o file.o
lub równowartość kilkaset razy, ponieważ istnieje kilkasetfile.c
plików. Kiedy robiłem tocmp
raczejccache
, zajęło mi to kilka minut - icmp
jest tak lekkie jakccache
. Problem polega na tym, że w Cygwin rozpoczęcie procesu zajmuje niemały czas, nawet w przypadku całkowicie trywialnego procesu.for f in src/*; do /bin/true.exe; done
zajmuje 30 sekund, więc tak. W każdym razie wolę mój edytor oparty na systemie Windows, a oprócz tego rodzaju problemów dotyczących czasu Cygwin działa całkiem dobrze z moim przepływem pracy jako lekkim miejscem do testowania rzeczy lokalnie, jeśli nie przesyłam na serwery kompilacji. Przydatne jest posiadanie mojej powłoki i edytora w tym samym systemie operacyjnym. :)To powinno zrobić to, czego potrzebujesz
Gdzie:
źródło
-J
jest specyficzne dla bsd; w GNU xargs jest-I
) i nie działa poprawnie, jeśli ten sam zestaw plików już nie istnieje w obu lokalizacjach (jeślitouch x/boo
wtedy grep daje miOnly in ./x: boo
co powoduje błędy w potoku). Użyj narzędzia zbudowanego do pracy, nprsync --checksum
.Lubię używać unison na rzecz,
rsync
ponieważ obsługuje wielu mistrzów, ponieważ już skonfigurowałem moje klucze ssh i VPN osobno.Dlatego w moim crontabie tylko jednego hosta pozwalam im synchronizować co 15 minut:
Wtedy mogę się rozwijać po obu stronach, a zmiany będą się rozprzestrzeniać. W rzeczywistości w przypadku ważnych projektów mam do 4 serwerów dublujących to samo drzewo (3 działają jednocześnie z cron, wskazując na ten, który tego nie robi). W rzeczywistości hosty Linux i Cygwin są mieszane - z wyjątkiem tego, że nie oczekuj wyczucia miękkich linków w win32 poza środowiskiem cygwin.
Jeśli pójdziesz tą drogą, zrób początkowe lustro po pustej stronie bez
-batch
, tjOczywiście istnieje konfiguracja ignorująca pliki kopii zapasowych, archiwa itp .:
źródło
unison
opcji oznaczającej „nie aktualizuj dat ostatniej modyfikacji pliku”. Czy jest jeden W przeciwnym razie jest to świetna odpowiedź na zupełnie inny problem.-times
robi to dla mnie Myślę, że Unison ma również tryb pracy na sucho.times=false
(lub rezygnacja-times
) by to zrobiło. Wcześniej nie wiem, jak mi tego brakowało. Dzięki!Chociaż
rsync --checksum
jest to poprawna odpowiedź, należy pamiętać, że ta opcja jest niezgodna z--times
, i--archive
obejmuje to--times
, więc jeśli chceszrsync -a --checksum
, naprawdę musiszrsync -a --no-times --checksum
.źródło