rsync comparar diretórios?

63

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

ls -alRe diffnão há opção aqui, já que existem hardlinks na fonte que tornam cada linha diferente. (Obviamente, eu poderia excluir esta coluna com perl.)

chris
fonte

Respostas:

46

Você provavelmente terá que executar algo como rsync -avun --deletenas duas direções.

Mas o que você está realmente tentando realizar?

Atualização :

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

"grep delet" porque cada linha é impressa: excluindo um arquivo ..

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

Nils
fonte
49

Para adicionar à resposta de Nils (para quem se deparar com isso através do Google), por padrão, rsyncapenas compara os tamanhos dos arquivos e os tempos de modificação para saber se existem diferenças. (Se são diferentes, faz mais, mas se são iguais, para por aí.)

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

rsync -avnc $SOURCE $TARGET

(A -uopção diz ao rsync para ignorar os arquivos mais recentes $TARGETque os ativados $SOURCE, o que você provavelmente não deseja se estiver comparando conteúdo.)

user98393
fonte
6
Se você deseja apenas que os dados sejam os mesmos, talvez queira adicionar --no-group --no-owner --no-perms --no-timesou alguma combinação destes com base em suas necessidades.
Flungo
11
@flungo, ou simplesmente usar um subconjunto das opções implícitas -aem vez de -a, por exemplorsync -rlDcnv --delete $SOURCE $TARGET
maxschlepzig
Por favor, adicione --deleteà lista os arquivos existentes apenas em$TARGET
Tom Hale
25

Apenas para aqueles menos familiarizados com rsync:

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

Ele imprimirá uma rsyncsaída usual ,

  • com um <nome do arquivo> em uma linha para cada arquivo "novo" no${SOURCE}
  • e uma linha "excluindo <nome do arquivo>" para cada arquivo "novo" em ${DEST}.

  • Também pode imprimir alguns avisos, como "pular arquivo não-regular <nome do arquivo>" para links simbólicos.

PS. Eu sei que é um PS terrível - mas foi realmente adicionado rapidamente. No entanto, aposto que podemos achar isso útil.


PPS. Como alternativa, 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 de arquivos não contiverem novas linhas, podemos classificar os dois *.md5arquivos e diffeles. (Porém, isso funcionará apenas para arquivos; ou seja, um diretório vazio em ambos os lados não será detectado.)

ジ ョ ー
fonte
16

Surpreendentemente, nenhuma resposta em 6 anos usa a -iopção ou fornece resultados agradáveis, então aqui vou eu:

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

Aqui está 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/ Rsignifica que o arquivo / dir aparece apenas no diretório Left ou Right.
  • Xsignifica que o arquivo aparece em ambos os lados, mas não é o mesmo (caso em que os próximos 11 caracteres dar mais informações. s, te pdetectar diferenças nas s ize, t ime e p ermissions respectivamente - para mais informações tentar man rsynce procurar --itemize-changes) .

Opções extras que você pode querer usar

Se você também quiser comparar o proprietário / grupo / permissões dos arquivos, adicione as opções -o/ -g/ -prespectivamente. Por fim, 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 -ctambém para comparar o conteúdo dos arquivos com o mesmo nome, hora e tamanho.

TLDR - Apenas me dê um script para ligar

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ê deseja 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

if [[ -z $2 ]] ; then
    echo "USAGE: $0 dir1 dir2 [optional rsync arguments]"
    exit 1
fi

set -e

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 funciona?

Estamos chamando o rsync assim:

rsync -rin ...

Usamos -i( --itemize-changes) para dizer ao rsync para imprimir uma linha de saída para cada arquivo que contém informações sobre quaisquer diferenças entre os dois diretórios. Precisamos -nsuprimir o comportamento normal do rsync (que é tentar sincronizar os dois diretórios, copiando / excluindo arquivos). também precisamos -rtrabalhar recursivamente para todos os arquivos / subdiretórios.

Chamamos rsync três vezes:

1ª chamada : imprima arquivos que não existem no Dir_B. Precisamos usar --ignore-existingpara ignorar arquivos que existem 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 --existingapenas para verificar os arquivos que aparecem nos dois diretórios.

rsync -rin --existing $DIR_A/ $DIR_B/
ndemou
fonte
Não conheço outras pessoas, mas estou usando seu script. Ótimo trabalho! obrigado
Marinaio 19/04
Muito obrigado! Eu precisava de alguns ajustes, vou compartilhá-los abaixo, caso alguém esteja procurando algo semelhante. Primeiro, eu queria executar o rsync remoto como usuário sudo, para isso eu adicionei --rsync-path="sudo rsync"a todos os comandos do rsync. Segundo, eu queria comparar o diretório local com o diretório remoto. Eu adicionei --rsh "ssh -p1234"porque no meu caso o SSH está sendo executado na porta 1234. Então chamei o script like diff-dirs [email protected]:/mnt/Vol1/dir1/ /localMnt/dir1 -c.
sen4ik 31/10
7

Entendo pela sua pergunta que você não deseja usar o diff on ls , mas também pode usar o diff recursivamente nos diretórios:

diff -rq DIR1 DIR2
Camion
fonte
2

Levei algumas tentativas para que isso funcionasse. A resposta de Nils exige que $TARGETtermine em um final /, conforme explicado por ジ ョ ー ジ.

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

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

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

Eu uso sedaqui para remover o líder deletingdas linhas de saída e imprimir apenas essas linhas.

Eu não uso a rsyncopção -cporque 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 suficiente nesses casos. Não tenho motivos para suspeitar que meus computadores sofram de problemas de inclinação do relógio ou que algo alterou maliciosamente os carimbos de hora. Além disso, o resultado de -cnão pode alterar a decisão de excluir um arquivo, apenas a decisão de atualizar ou manter um arquivo.

Também uso -ue -a(em vez de -r), para poder reutilizar a linha de comando posteriormente 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
Orafu
fonte
0

Eu tenho outra idéia 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 Isso diz ao rsync para copiar diretórios recursivamente.

-n Isso faz com que o rsync execute uma execução de avaliação que não faça nenhuma alteração.

zhao Tony
fonte