Chtěl bych zkopírovat sadu souborů z adresáře A do adresáře B s tím, že pokud je soubor v adresáři A totožný se souborem v adresáři B, tento soubor by neměl být zkopírován (a proto by jeho doba modifikace neměla být aktualizováno). Existuje způsob, jak to udělat s existujícími nástroji, aniž by k tomu musel psát vlastní skript?
Abych trochu rozpracoval svůj případ použití: Autogeneruji spoustu .c
soubory v dočasném adresáři (způsobem, který je musí všechny bezpodmínečně vygenerovat), a když je znovu vygeneruji, chtěl bych zkopírovat pouze ty, které se změnily, do skutečného zdrojového adresáře, přičemž nezměněné zůstanou ty nedotčené (s jejich starými časy vytvoření), takže make
bude vědět, že je není třeba překompilovat. (Ne všechny vygenerované soubory jsou .c
soubory, takže musím udělat binární srovnání spíše než textová srovnání.)
(Jako poznámka: Toto vyrostlo z otázky, kterou jsem položil https://stackoverflow.com/questions/8981552/speeding-up-file-comparions-with-cmp-on-cygwin/8981762#8981762 , kde jsem se snažil zrychlit soubor skriptu, který jsem použil k provedení této operace, ale zdá se mi, že bych se měl opravdu zeptat, zda existuje lepší způsob, jak to udělat, než napsat svůj vlastní skript - zejména proto, že nějaký jednoduchý způsob, jak to provést ve skriptu Shell, vyvolá něco jako cmp
na každém páru souborů a spuštění všech těchto procesů trvá příliš dlouho.)
rsync je pravděpodobně tím nejlepším nástrojem. Na tomto příkazu je spousta možností, takže si přečtěte manuálová stránka . Myslím, že chcete volbu --checksum nebo --ignore-times
Můžete použít -u
přepněte na cp
takto:
$ cp -u [source] [destination]
Ze stránky man:
-u, --update
copy only when the SOURCE file is newer than the destination file or
when the destination file is missing
Při použití rsync --checksum
je dobrý obecný způsob, jak „kopírovat, pokud se změní“, ve vašem konkrétním případě existuje ještě lepší řešení!
Pokud se chcete vyhnout zbytečnému překompilování souborů, měli byste použít ccache , který byl vytvořen přesně pro tento účel! Ve skutečnosti se nejen vyhne zbytečným překompilováním automaticky generovaných souborů, ale také to urychlí, kdykoli uděláte make clean
a znovu zkompilujte od nuly.
Dále jsem si jistý, že se zeptáte: "Je to bezpečné?" Ano, jak to webové stránky upozorňují:
Je to bezpečné?
Ano. Nejdůležitějším aspektem mezipaměti kompilátoru je vždy produkovat přesně stejný výstup, jaký by vytvořil skutečný kompilátor. To zahrnuje poskytnutí přesně stejných souborů objektů a přesně stejných varování kompilátoru, která by byla vytvořena, pokud použijete skutečný kompilátor. Jediným způsobem, jak byste měli vědět, že používáte ccache, je rychlost.
A je to snadno použitelné , stačí jej přidat jako předponu do CC=
řádek vašeho makefile (nebo můžete použít symlinks, ale makefile způsob je pravděpodobně lepší).
To by mělo dělat, co potřebujete
diff -qr ./x ./y | awk '{print $2}' | xargs -n1 -J% cp % ./y/
Kde:
Rád používám nison ve prospěch rsync
, protože podporuje více mistrů, , kteří již nastavili moje ssh klíče a vpn samostatně.
Takže v mém crontabu pouze jednoho hostitele jsem je nechal synchronizovat každých 15 minut:
*/15 * * * * [-z "$ (pidof unison)"] && (timeout 25m unison -sortbysize --ui text -batch -times/home/master ssh: //192.168.1.12//home/master -path dev -logfile /tmp/sync.master.dev.log) &> /tmp/sync.master.dev.log
Pak se mohu vyvíjet na obou stranách a změny se budou šířit. Ve skutečnosti pro důležité projekty mám až 4 servery odrážející stejný strom (3 běžící unison od cron, ukazující na ten, který ne). Ve skutečnosti se hostitelé systémů Linux a Cygwin smíšili - kromě toho neočekávejte smysl z měkkých odkazů ve win32 mimo prostředí cygwin.
Pokud jdete touto cestou, udělejte počáteční zrcadlo na prázdné straně bez -batch
, tj.
unison -ui text -times /home/master ssh://192.168.1.12//home/master -path dev
Samozřejmě existuje konfigurace pro ignorování záložních souborů, archivů atd .:
~/.unison/default.prf :
# Unison preferences file
ignore = Name {,.}*{.sh~}
ignore = Name {,.}*{.rb~}
ignore = Name {,.}*{.bak}
ignore = Name {,.}*{.tmp}
ignore = Name {,.}*{.txt~}
ignore = Name {,.}*{.pl~}
ignore = Name {.unison.}*
ignore = Name {,.}*{.Zip}
# Use this command for displaying diffs
diff = diff -y -W 79 --suppress-common-lines
ignore = Name *~
ignore = Name .*~
ignore = Path */pilot/backup/Archive_*
ignore = Name *.o
Zatímco rsync --checksum
je správná odpověď. Upozorňujeme, že tato možnost není kompatibilní s --times
a to --archive
zahrnuje --times
, takže pokud chcete rsync -a --checksum
, opravdu musíte rsync -a --no-times --checksum
.