it-swarm-eu.dev

Jak mohu provést operaci „kopírování, pokud byla změněna“?

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.)

37
Brooks Moses

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

31
Adam Terrey

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
19
gu1

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ší).

7
aculich

To by mělo dělat, co potřebujete

diff -qr ./x ./y | awk '{print $2}' | xargs -n1 -J% cp % ./y/

Kde:

  • x je vaše aktualizovaná/nová složka
  • y je cíl, do kterého chcete kopírovat
  • awk vezme druhý argument každého řádku z příkazu diff (možná budete potřebovat nějaké další věci pro názvy souborů s mezerou - nemůžete to hned vyzkoušet)
  • xargs -J% vloží název souboru do cp na správné místo
4
Patkos Csaba

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
3
Marcos

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.

1
Vladimir Kornea