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 for idêntico a um arquivo no diretório B, esse arquivo não deverá ser copiado (e, portanto, seu tempo de modificação não deverá ser Atualizada). Existe uma maneira de fazer isso com as ferramentas existentes, sem escrever meu próprio script para fazer isso?
Para elaborar um pouco do meu caso de uso: estou gerando automaticamente vários .c
arquivos em um diretório temporário (por um método que precisa gerar todos eles incondicionalmente) e, quando eu os gerar novamente, gostaria de copiar apenas os que foram alterados para o diretório de origem real, deixando os inalterados intocados (com seus antigos tempos de criação), para que make
saibam que não é necessário recompilá-los. ( .c
Porém, nem todos os arquivos gerados são arquivos, portanto, preciso fazer comparações binárias em vez de comparações de texto.)
(Como uma observação: isso surgiu da pergunta que fiz em https://stackoverflow.com/questions/8981552/speeding-up-file-comparions-with-cmp-on-cygwin/8981762#8981762 , onde estava tentando para acelerar o arquivo de script que eu estava usando para fazer essa 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 existe uma maneira simples de fazer isso em um shell O script invocará algo como cmp
em cada par de arquivos e iniciar todos esses processos leva muito tempo.)
fonte
diff -qr dirA dirB
para ver quais arquivos são exclusivosdirA
edirB
, respectivamente.rsync -avnc
ou o longo caminhorsync --archive --verbose --dry-run --checksum
.Respostas:
O rsync é provavelmente a melhor ferramenta para isso. Existem muitas opções nesse comando, então leia a página de manual . Eu acho que você quer a opção --checksum ou o --ignore-times
fonte
-t
opção for especificada) ou para o tempo de sincronização (se-t
não for especificado).rsync
não. Se eu fizer isso :,mkdir src dest; echo a>src/a; rsync -c src/* dest; sleep 5; touch src/a; rsync -c src/* dest
entãostat dest/a
mostra que mtime e ctime são 5 segundos mais antigos que os desrc/a
.--checksum
opção e, embora linux.die.net/man/1/rsync não contenha absolutamente nada que implique que isso tenha algum efeito sobre a atualização da data da modificação, ainda assim deixa a data de modificação do destino intocado. (Por outro lado, a--ignore-times
opção não tem esse efeito; com ela a data da modificação ainda é atualizada.) Dado que isso parece ser totalmente indocumentado, posso confiar nisso?rsync
o fluxo de trabalho é: 1) verifique se o arquivo precisa ser atualizado; 2) se sim, atualize o arquivo. A--checksum
opção diz que não deve ser atualizado; portantorsync
, não prossiga para a etapa 2).--ignore-times
without--checksum
copia todos os arquivos e também atualiza o registro de data e hora, mesmo que os arquivos sejam idênticos.Você pode usar o
-u
comutador paracp
:Na página do manual:
fonte
-u
bandeira faz e como funciona e como isso ajudaria o OP. No entanto, nesse caso em particular, isso não ajudaria o OP, pois copiaria arquivos idênticos se eles fossem mais novos e, portanto, alteraria seu registro de data e hora, que é precisamente o que o OP deseja evitar.Embora o uso
rsync --checksum
seja uma boa maneira geral de "copiar se alterado", no seu caso específico, 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 esse fim! De fato, ele não apenas evitará recompilações desnecessárias dos arquivos gerados automaticamente, mas também acelerará as coisas sempre que você fizer
make clean
e recompilar do zero.Em seguida, tenho certeza que você perguntará: "É seguro?" Bem, sim, como o site aponta:
E é fácil usá- lo apenas adicionando-o como um prefixo na
CC=
linha do seu makefile (ou você pode usar links simbólicos, mas a maneira do makefile provavelmente é melhor).fonte
ccache file.c -o file.o
ou equivalente, várias centenas de vezes, porque existem várias centenas defile.c
arquivos. Quando eu estava fazendo isso comcmp
, em vez deccache
, levou vários minutos - ecmp
é tão leve quantoccache
. O problema é que, no Cygwin, iniciar um processo leva um tempo não desprezível, mesmo para um processo completamente trivial.for f in src/*; do /bin/true.exe; done
leva 30 segundos, então sim. Enfim, prefiro meu editor baseado no Windows e, além desse tipo de problema de tempo, o Cygwin funciona muito bem com meu fluxo de trabalho como o local mais leve para testar as coisas localmente, se não estiver carregando nos servidores de compilação. É útil ter meu shell e meu editor no mesmo sistema operacional. :)Isso deve fazer o que você precisa
Onde:
fonte
-J
é específico para bsd; com GNU xargs é-I
) e não funciona corretamente se o mesmo conjunto de arquivos já não existir nos dois locais (se eutouch x/boo
então grep me fornecerOnly in ./x: boo
que causa erros no pipeline). Use uma ferramenta criada para o trabalho, comorsync --checksum
.Eu gosto de usar o uníssono a favor
rsync
porque suporta múltiplos mestres, já tendo configurado minhas chaves ssh e vpn separadamente.Portanto, no crontab de apenas um host, eu os deixo sincronizar a cada 15 minutos:
Então eu posso estar desenvolvendo dos dois lados e as mudanças serão propagadas. De fato, para projetos importantes, tenho até 4 servidores espelhando a mesma árvore (3 são executados em uníssono no cron, apontando para o que não é). De fato, os hosts Linux e Cygwin são mistos - exceto que não esperam senso de links suaves no win32 fora do ambiente cygwin.
Se você seguir esta rota, faça o espelho inicial do lado vazio sem o
-batch
, ou seja,Claro que há uma configuração para ignorar arquivos de backup, arquivos, etc .:
fonte
unison
opção que significa "não atualizar datas da última modificação do arquivo". Existe um? Caso contrário, essa é uma ótima resposta para um problema completamente diferente.-times
faz isso por mim. O Unison também tem um modo de funcionamento a seco, eu acho.times=false
(ou deixar de fora-times
) faria isso. Não sei como perdi isso na documentação antes. Obrigado!Embora
rsync --checksum
seja a resposta correta, observe que esta opção é incompatível com--times
, e isso--archive
inclui--times
, portanto, se você quiserrsync -a --checksum
, realmente precisarársync -a --no-times --checksum
.fonte