rsync compara os diretórios?

53

É possível comparar dois diretórios com rsync e imprimir apenas as diferenças? Existe uma opção de execução a seco, mas quando eu aumentei a verbosidade para um certo nível, todos os arquivos comparados são mostrados.

ls -alR e diff não é uma opção aqui, pois existem hardlinks na origem, tornando cada linha diferente. (Claro, eu poderia deletar essa coluna com perl).

    
por chris 01.12.2012 / 12:18

7 respostas

41

Você provavelmente terá que executar algo como rsync -avun --delete em ambas as direções.

Mas o que você está realmente tentando realizar?

Atualizar :

rsync -avun --delete $TARGET $SOURCE |grep "^deleting " lhe dará uma lista de arquivos que não existem no diretório de destino.

"grep delet" porque cada linha imprime: delet ing ..file ..

rsync -avun $SOURCE $TARGET fornecerá uma lista de arquivos "diferentes" (incluindo novos arquivos).

    
por 02.12.2012 / 23:14
43

Para adicionar a resposta de Nils (para qualquer um que se deparar com isso via Google), por padrão, rsync compara apenas os tamanhos de arquivo e os horários de modificação para informar se há alguma diferença. (Se eles são diferentes, ele faz mais, mas se eles são os mesmos, ele pára por aí).

Se você quiser comparar o arquivo real conteúdo , mesmo para arquivos que tenham o mesmo tamanho e hora da última modificação, adicione o sinalizador -c para informar rsync para comparar os arquivos usando uma soma de verificação .

rsync -avnc $SOURCE $TARGET

(A opção -u diz ao rsync para ignorar arquivos que são mais recentes em $TARGET do que em $SOURCE , o que você provavelmente não deseja se estiver comparando o conteúdo.)

    
por 07.01.2015 / 15:35
17

Apenas para pessoas menos familiarizadas com rsync :

rsync -rvnc --delete ${SOURCE}/ ${DEST}
  • -n : bit mais importante - não não altera nada;
  • -rc : compare apenas o conteúdo (caso contrário use -ac );
  • -v : lista os arquivos)
  • --delete : procure por uma diferença simétrica, não unidirecional.
  • Finalmente, / significa "procurar dentro do diretório e comparar seus conteúdos com o destino".

It will print a usual rsync output,

  • with one <filename> on a line for every "new" file in ${SOURCE}
  • and one "deleting <filename>" line for each "new" file in ${DEST}.

  • It may also print a few warnings, like "skipping non-regular file <filename>" for symlinks.

PS. Eu sei que é um PS terrível - mas foi de fato adicionado em uma corrida. No entanto, aposto que alguém pode achar isso útil.

PPS. Alternativamente, também se poderia fazer
find $SOURCE -type f -exec md5sum {} \; | tee source.md5
find $DEST   -type f -exec md5sum {} \; | tee dest.md5

Se os nomes dos arquivos não contiverem novas linhas, podemos classificar os arquivos *.md5 e diff . (Isso funcionará apenas para arquivos, isto é, um diretório vazio em ambos os lados não será detectado.)

    
por 13.03.2017 / 13:43
3

Eu entendo da sua pergunta que você não quer usar diff em ls , mas você também pode usar diff recursivamente em diretórios:

diff -rq DIR1 DIR2
    
por 03.07.2017 / 18:58
1

Demorei algumas tentativas para que isso funcionasse. A resposta de Nils requer que $TARGET termine em / , conforme explicado por ジ ョ ー ジ.

Aqui está uma versão que adiciona explicitamente o / :

rsync -avun --delete ${TARGET}/ ${SOURCE}  | sed -ne 's/^deleting *//p'

Isso fornece a lista de arquivos que estão abaixo do diretório ${SOURCE} , mas não abaixo do diretório ${TARGET} .

Eu uso sed aqui para remover o deleting das linhas de saída e imprimir apenas essas linhas.

Eu não uso o rsync option -c porque comparar o conteúdo do arquivo seria muito mais lento para meus casos de uso, e comparar apenas tamanhos de arquivo e tempos de modificação também parece ser suficiente nesses casos. Não tenho motivos para suspeitar que meus computadores sofram com problemas de distorção de clock ou que algo tenha alterado maliciosamente os timestamps. Além disso, o resultado de -c não pode alterar a decisão de excluir um arquivo, apenas a decisão de atualizar ou manter um arquivo.

Eu também uso -u e -a (em vez de -r ), para que depois eu possa reutilizar a linha de comando e alterá-la para copiar diretórios e arquivos selecionados de ${SOURCE} para ${TARGET} , assim:

rsync -avu ${SOURCE}/{dirA,dirB,fileX} ${TARGET}   # copy some files
    
por 15.05.2018 / 08:14
1

Surpreendentemente, nenhuma resposta em 6 anos usa a opção -i ou dá uma boa saída, então aqui vou:

TLDR - Apenas me mostre os comandos

rsync -rin --ignore-existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^[^ ]* /L             /'
rsync -rin --ignore-existing "$RIGHT_DIR"/ "$LEFT_DIR"/|sed -e 's/^[^ ]* /R             /'
rsync -rin --existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^/X /'

Entendendo a saída

Veja um exemplo da saída:

L             file-only-in-Left-dir
R             file-only-in-right-dir
X >f.st...... file-with-dif-size-and-time
X .f...p..... file-with-dif-perms

Observe o primeiro caractere de cada linha:

  • L / R significa que o arquivo / dir aparece apenas no diretório L eft ou R ight.
  • X significa que o arquivo aparece nos dois lados, mas não é o mesmo (nesse caso, os próximos 11 caracteres fornecem mais informações. s , t e p descrevem as diferenças em s ize, t ime e p ermissões respectivamente - para mais informações, tente man rsync e procure por --itemize-changes ).

Opções extras que você pode usar

Se você quiser comparar também o proprietário / grupo / permissões dos arquivos, adicione as opções -o / -g / -p , respectivamente. Finalmente, observe que, por padrão, o rsync considera dois arquivos iguais, se eles tiverem o mesmo nome, hora e tamanho. Isso é extremamente rápido e na maioria das vezes é mais do que suficiente, mas se você quiser ter 100% de certeza, adicione -c para comparar também o conteúdo de arquivos com o mesmo nome, hora & tamanho.

TLDR - Apenas me dê um script para chamar

Aqui está. Chame assim:

diff-dirs Left_Dir Right_Dir [options]

Todas as opções mencionadas acima na seção "Opções extras que você pode desejar usar" também se aplicam aqui.

#!/bin/bash
# Compare two directories using rsync and print the differences
# CAUTION: options MUST appear after the directories
#
# SYNTAX
#---------
# diff-dirs Left_Dir Right_Dir [options]
#
# EXAMPLE OF OUTPUT
#------------------
# L             file-only-in-Left-dir
# R             file-only-in-right-dir
# X >f.st...... file-with-dif-size-and-time
# X .f...p..... file-with-dif-perms
#
# L / R mean that the file/dir appears only at the 'L'eft or 'R'ight dir. 
#
# X     means that a file appears on both sides but is not the same (in which
#       case the next 11 characters give you more info. In most cases knowing
#       that s,t,T and p depict differences in Size, Time and Permissions 
#       is enough but 'man rsync' has more info
#       (look at the --itemize-changes option)
#
# OPTIONS
#---------
# All options are passed to rsync. Here are the most useful for the purpose
# of directory comparisons:
#
# -c will force comparison of file contents (otherwise only
#    time & size is compared which is much faster)
#
# -p/-o/-g will force comparison of permissions/owner/group

LEFT_DIR=$1; shift
RIGHT_DIR=$1; shift
OPTIONS="$*"

# Files that don't exist in Right_Dir
rsync $OPTIONS -rin --ignore-existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^[^ ]* /L             /'
# Files that don't exist in Left_Dir
rsync $OPTIONS -rin --ignore-existing "$RIGHT_DIR"/ "$LEFT_DIR"/|sed -e 's/^[^ ]* /R             /'
# Files that exist in both dirs but have differences
rsync $OPTIONS -rin --existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^/X /'

Como isso funciona?

O núcleo do trabalho é executado chamando o rsync assim:

rsync -rin --ignore-existing $DIR_A/ $DIR_B/

Usamos: -i para dizer ao rsync para imprimir uma linha de saída para cada arquivo formatado de uma maneira especial *, -n para suprimir o comportamento normal do rsync (para tentar copiar / excluir / sincronizar os dois diretórios) , -r para trabalhar recursivamente para todos os arquivos / sub-diretórios.

Nós chamamos rsync três vezes:

Primeira chamada : imprime arquivos que não existem no Dir_B. Precisamos usar --ignore-existing para ignorar os arquivos existentes nos dois lados.

rsync -rin --ignore-existing $DIR_A/ $DIR_B/

2ª chamada : exatamente como antes, mas trocamos a ordem de DIR_A / DIR_B.

3ª chamada : Finalmente, usamos --existing para verificar apenas os arquivos que aparecem nos dois diretórios.

rsync -rin --existing $DIR_A/ $DIR_B/

Notas

*: use man rsync e procure por --itemize-changes

    
por 17.08.2018 / 17:51
0

Eu tenho outra ideia de fazer isso:

rsync -rn --out-format=FILEDETAIL::%n  $TARGET $SOURCE  | grep "^FILEDETAIL"

Você pode combinar "FILEDETAIL ::" com a saída do comando. Além disso, você pode alterar a string "FILEDETAIL ::". O "% n" é o nome do arquivo.

-r Isto diz ao rsync para copiar diretórios recursivamente.

-n Isso faz com que o rsync realize uma execução de teste que não faz alterações.

    
por 19.09.2018 / 13:37