O rsync é provavelmente a melhor ferramenta para isso. Existem muitas opções neste comando, por isso leia a página de manual . Eu acho que você quer a opção --checksum ou --ignore-times
Eu gostaria de copiar um conjunto de arquivos do diretório A para o diretório B, com a ressalva de que se um arquivo no diretório A é idêntico a um arquivo no diretório B, esse arquivo não deve ser copiado (e, portanto, seu tempo de modificação não deve ser atualizado). Existe uma maneira de fazer isso com ferramentas existentes, sem escrever meu próprio script para fazer isso?
Para elaborar um pouco sobre o meu caso de uso: estou autogerando um monte de arquivos .c
em um diretório temporário (por um método que tem que gerar todos eles incondicionalmente), e quando eu os re-gerar, eu Gostaria de copiar apenas os que foram alterados no diretório de origem, deixando os inalterados intactos (com seus tempos de criação antigos) para que make
saiba que não precisa recompilá-los. (Nem todos os arquivos gerados são .c
arquivos, então eu preciso fazer comparações binárias ao invés de comparações de texto.)
(Como nota: isso cresceu fora da questão que eu perguntei em link , onde eu estava tentando acelerar o arquivo de script que eu estava usando para fazer esta operação, mas me ocorre que eu realmente deveria perguntar se há uma maneira melhor de fazer isso do que escrever meu próprio script - especialmente porque qualquer maneira simples de fazer isso em um shell script invocará algo como cmp
em cada par de arquivos, e iniciar todos esses processos leva muito tempo.)
O rsync é provavelmente a melhor ferramenta para isso. Existem muitas opções neste comando, por isso leia a página de manual . Eu acho que você quer a opção --checksum ou --ignore-times
Você pode usar a opção -u
como cp
da seguinte forma:
$ cp -u [source] [destination]
Da página do manual:
-u, --update
copy only when the SOURCE file is newer than the destination file or
when the destination file is missing
Enquanto usar rsync --checksum
é uma boa maneira geral de "copiar se alterado", no seu caso particular, existe uma solução ainda melhor!
Se você deseja evitar a recompilação desnecessária de arquivos, use o ccache que foi criado exatamente para essa finalidade! Na verdade, não só evitará recompilações desnecessárias de seus arquivos gerados automaticamente, como também acelerará as coisas sempre que você make clean
e recompilará a partir do zero.
Em seguida, tenho certeza de que você perguntará: "É seguro?" Bem, sim, como o site aponta:
Is it safe?
Yes. The most important aspect of a compiler cache is to always produce exactly the same output that the real compiler would produce. This includes providing exactly the same object files and exactly the same compiler warnings that would be produced if you use the real compiler. The only way you should be able to tell that you are using ccache is the speed.
E é fácil de usar apenas adicionando-o como um prefixo na linha CC=
do seu makefile (ou você pode usar links simbólicos, mas o caminho do makefile provavelmente é melhor).
Isso deve fazer o que você precisa
diff -qr ./x ./y | awk '{print $2}' | xargs -n1 -J% cp % ./y/
Onde:
Eu gosto de usar unison em favor de rsync
porque ele suporta múltiplos mestres, tendo já configurado minhas chaves ssh e vpn separadamente.
Então, no meu crontab de apenas um host, eu os deixo sincronizar a cada 15 minutos:
*/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
Então eu posso estar desenvolvendo em ambos os lados e as mudanças se propagam. De fato, para projetos importantes, eu tenho até 4 servidores espelhando a mesma árvore (3 rodam em uníssono do cron, apontando para o que não funciona). Na verdade, os hosts Linux e Cygwin são mistos - exceto por não esperar que os links suaves surjam no win32 fora do ambiente cygwin.
Se você seguir esse caminho, crie o espelho inicial no lado vazio sem o -batch
, ou seja,
unison -ui text -times /home/master ssh://192.168.1.12//home/master -path dev
Claro que há uma configuração para ignorar arquivos de backup, arquivos, etc .:
~/.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
Embora rsync --checksum
seja a resposta correta, observe que essa opção é incompatível com --times
e que --archive
inclui --times
, portanto, se você quiser rsync -a --checksum
, realmente precisará rsync -a --no-times --checksum
.