web-dev-qa-db-ja.com

2つのフォルダーを比較して、その違いを3番目のフォルダーにコピーするにはどうすればよいですか?

次の3つのフォルダーがあります。

  • フォルダーcurrent、現在のファイルが含まれています
  • フォルダーold、同じファイルの古いバージョンが含まれています
  • folder difference、これは単なる空のフォルダです

どのようにoldcurrentを比較し、currentで異なる(またはまったく新しい)ファイルをdifferenceにコピーしますか=?


私はあちこちを検索しましたが、取り組むのは簡単なことのようですが、私の特定の例ではうまく機能しません。ほとんどのソースはrsyncの使用を提案していたため、次のコマンドで終了しました。

rsync -ac --compare-dest=../old/ new/ difference/

ただし、これにより、すべてのファイルがnewからdifferenceにコピーされます。これはoldと同じファイルでも同様です。

それが役立つ場合(おそらくコマンドは問題なく、障害は他の場所にあります)、これは私がこれをテストした方法です:

  1. 3つのフォルダを作りました。
  2. oldで内容の異なるテキストファイルをいくつか作成しました。
  3. oldからnewにファイルをコピーしました。
  4. newの一部のファイルの内容を変更し、いくつかのファイルを追加しました。
  5. 上記のコマンドを実行して、結果をdifferenceで確認しました。

私は過去数日間の解決策を探していましたが、いくつかの助けに本当に感謝します。必ずしもrsyncを使用する必要はありませんが、できれば何が間違っているのかを知りたいのですが。

23
Thane

Rsyncやdiffなどの既存のLinuxコマンドでそれを実行できるかどうかはわかりません。しかし、私の場合、pythonにはファイル比較のための「filecmp」モジュールがあるため、Pythonを使用して独自のスクリプトを作成する必要がありました。スクリプト全体と使用法を個人用サイトに投稿しました-- http://linuxfreelancer.com/

使い方は簡単です。新しいディレクトリ、古いディレクトリ、差分ディレクトリの絶対パスをこの順序で指定します。

#!/usr/bin/env python

import os, sys
import filecmp
import re
from distutils import dir_util
import shutil
holderlist=[]

def compareme(dir1, dir2):
    dircomp=filecmp.dircmp(dir1,dir2)
    only_in_one=dircomp.left_only
    diff_in_one=dircomp.diff_files
    dirpath=os.path.abspath(dir1)
    [holderlist.append(os.path.abspath( os.path.join(dir1,x) )) for x in only_in_one]
    [holderlist.append(os.path.abspath( os.path.join(dir1,x) )) for x in diff_in_one]
    if len(dircomp.common_dirs) > 0:
        for item in dircomp.common_dirs:
            compareme(os.path.abspath(os.path.join(dir1,item)), os.path.abspath(os.path.join(dir2,item)))
        return holderlist

def main():
 if len(sys.argv) > 3:
   dir1=sys.argv[1]
   dir2=sys.argv[2]
   dir3=sys.argv[3]
 else:
   print "Usage: ", sys.argv[0], "currentdir olddir difference"
   sys.exit(1)

 if not dir3.endswith('/'): dir3=dir3+'/'

 source_files=compareme(dir1,dir2)
 dir1=os.path.abspath(dir1)
 dir3=os.path.abspath(dir3)
 destination_files=[]
 new_dirs_create=[]
 for item in source_files:
   destination_files.append(re.sub(dir1, dir3, item) )
 for item in destination_files:
  new_dirs_create.append(os.path.split(item)[0])
 for mydir in set(new_dirs_create):
   if not os.path.exists(mydir): os.makedirs(mydir)
#copy pair
 copy_pair=Zip(source_files,destination_files)
 for item in copy_pair:
   if os.path.isfile(item[0]):
    shutil.copyfile(item[0], item[1])

if __name__ == '__main__':
 main()
7
Daniel t.

私の場合、問題は何であるかを理解しました:

比較していたファイルのタイムスタンプが異なっていました。 -a引数を使用するべきではありませんでした。ファイルをコピーするときにrsyncがタイムスタンプを保持しようとしたためです。私のために働いたコマンドは:

rsync -rvcm --compare-dest=../old/ new/ difference/
21
Thane

これは一部の読者を助けるかもしれません:Windowsでは、古い、小さなフリーウェアプログラム-Third Dir-がここで求められていることを正確に実行します。開発者のRobertVašíčekからは入手できなくなりました。しかし、私はそれがオンラインのいくつかのリポジトリを介して見つけることができると確信しています。

これは彼のサイトに残っている開発者の説明です:

3番目のディレクトリ:珍しいディレクトリシンクロナイザー-異なるファイルが3番目のディレクトリにコピーされます。抽出することは非常に便利です。固定ディスクの巨大なディレクトリツリーから一時フォルダに新しい写真または編集した写真を追加し、それらをアーカイブCDに追加します(注-元のファイルはCDと比較されます)。バージョン1.4、サイズ23kB。 2005年2月12日作成。

履歴:バージョン1.14-何万ものファイルを比較するとより効率的になります。

1
Steve

山猫が追加したThaneによるrsyncの方法はうまくいきますが、空のディレクトリを残します。私にとっての最終的な解決策は2つのステップでした。最初にフルパスでrsyncを呼び出し、次にfindコマンドですべての空のディレクトリを削除しました。

rsync -rvcm --compare-dest=/tmp/org/ /tmp/new/ /tmp/difference/
find /tmp/difference/ -d -type d -empty -exec rmdir {} \; -print

--linksオプションを使用した場合よりも、rsyncはシンボリックリンクを保持せず、代わりに宛先データをコピーしたことに注意してください。

0
PierreL