回答:
diffツールを使用できます。オプション-qおよび-rを参照してください。
-q --brief
Output only whether files differ.
-r --recursive
Recursively compare any subdirectories found.
例:
diff -qr dir1 dir2
Only in
ディレクトリが理想的なコピーであっても、それが表示されるという意味のない情報で散らばっている、まったくひどく読みにくい出力です。変更を古いリビジョンと比較し、リビジョン全体を別のディレクトリにダウンロードし、標準のSVNツールを使用して比較する必要がありました。それが唯一の方法のように思えます…
diffutils
パッケージには、lsdiff
ツールを。の出力diff -u
をlsdiffに渡すだけです:
diff -u --other-diff-options path1 path2 | lsdiff
patchutils
私のパッケージに含まれていました(CentOS 5.x)。
変更されたファイルの名前のみを取得するには、次のコマンドを使用します。
diff -r dirt1 dir2 --brief | sed 's/^Only in \([^:]*\): /\1\//' | sed 's/^Files \(.*\) and .* differ/\1/'
一部のファイルをオブジェクトファイルまたはライブラリファイルとして除外する必要がある場合は、次を使用できます。
diff -r dirt1 dir2 --brief --exclude "*.o" --exclude "*.a" | sed 's/^Only in \([^:]*\): /\1\//' | sed 's/^Files \(.*\) and .* differ/\1/'
プログラムで新しいファイルまたは変更されたファイルのリストを作成するには、rsync、sort、およびuniqを使用するのが最善の解決策です。
(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq
この例を使用して説明します。2つのdokuwikiリリースを比較して、変更されたファイルと新しく作成されたファイルを確認します。
私たちは、wgetコマンドでタールを取得したディレクトリにそれらを抽出old/
してnew/
:
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29d.tgz
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29.tgz
mkdir old && tar xzf dokuwiki-2014-09-29.tgz -C old --strip-components=1
mkdir new && tar xzf dokuwiki-2014-09-29d.tgz -C new --strip-components=1
rsyncとdiffの比較がここに示されているように、rsyncを一方向に実行すると、新しく作成されたファイルを見逃す可能性があります。
rsync -rcn --out-format="%n" old/ new/
次の出力が生成されます。
VERSION
doku.php
conf/mime.conf
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php
一方向でのみrsyncを実行すると、新しく作成されたファイルが失われ、逆の方法では削除されたファイルが失われます。diffの出力を比較してください。
diff -qr old/ new/
次の出力が生成されます。
Files old/VERSION and new/VERSION differ
Files old/conf/mime.conf and new/conf/mime.conf differ
Only in new/data/pages: playground
Files old/doku.php and new/doku.php differ
Files old/inc/auth.php and new/inc/auth.php differ
Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ
両方の方法でrsyncを実行し、出力をソートして重複を削除するdata/pages/playground/
と、data/pages/playground/playground.txt
最初にディレクトリとファイルが失われたことがわかります。
(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq
次の出力が生成されます。
VERSION
conf/mime.conf
data/pages/playground/
data/pages/playground/playground.txt
doku.php
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php
rsync
これらの引数で実行されます:
-r
「ディレクトリに再帰する」、 -c
同じサイズのファイルを比較し、「mod-timeとサイズではなく、チェックサムに基づいてスキップする」だけで、 -n
「変更を加えずに試運転を実行する」--out-format="%n"
「指定されたFORMATを使用して更新を出力する」、これはファイル名のみの「%n」ですの出力(ファイルのリスト)はrsync
、を使用して結合およびソートされsort
、このソートされたリストは、uniq
これはトリックをするかもしれません:
compare_dirs()
{
# Shows which files and directories exist in one directory but not both
if [ $# -ne 2 ]
then
echo "Usage: compare_dirs dir1 dir2" >&2
return 2
fi
for path
do
if [ ! -d "$path" ]
then
echo "Not a directory: $path" >&2
return 1
fi
done
comm -3 \
<(cd -- "$1" && find . -printf '%P\0' | sort -z | quote_shell) \
<(cd -- "$2" && find . -printf '%P\0' | sort -z | quote_shell)
}
通常、ファイルをSubVersionやgitなどの何らかのバージョン管理システムに配置します。これらはすぐに使用できるためです。
ただし、dir1でforループを使用して簡単なスクリプトを実行し、すべてのファイルをdir2のファイルと比較できます。forループは、diffからの終了コードを調べて、ファイルが異なっていたかどうかを知ることができます。
たぶんこのようなもの:
for f in `(cd dir1 ; find .)`
do
diff $f ../dir2/$f
if [ "$?" == "0" ]
then
echo same
else
echo diff: $f
fi
done
注:スクリプトはテストされていないため、上記の例は「bashに触発された擬似コード」です...
もう一度行ってみましょう。ただしgitを使用します
プレイするサンプルファイルを作成します
mkdir -p dir1/test1/test11
mkdir -p dir1/test1/test12
mkdir -p dir1/test1/test13
echo "Test1" >> dir1/test1/test11/t1.txt
echo "Test2" >> dir1/test1/test12/t2.txt
echo "Test3" >> dir1/test1/test13/t3.txt
#And a dir to work in
mkdir gitdir
次に、dirを入力してdir1をインポートします
cd gitdir/
git init .
cp -r ../dir1/* .
git add .
git commit -m 'dir1'
外に出てdir1を変更します(したがって、dir1になります)
cd ..
echo "Test2" > dir1/test1/test11/t1.txt
次に、git dirに移動して、新しいディレクトリをインポートします
cd gitdir/
cp -r ../dir1/* .
次に、何が変更されたかをgitに尋ねます(statusコマンドを使用)
git status -s
出力は、次のような変更を含むリストです。
M test1/test11/t1.txt
これはrsyncに似ています:宛先の新しいファイルがいつ上書きされるかを示します(後で確認されますが、重複はありません)。
質問で示されているように、「diff -q -r」を使用するには、何らかの処理が必要になる場合があります。質問では、出力の形式を指定しませんでした。回答はさまざまな種類のレポートを提供します。
rsync
これは、に比べてはるかに高速であるため、この目的に役立つツールですdiff
。ただし、@ nilsが提案するソリューションは、古いディレクトリツリーと新しいディレクトリツリーの実際の違いよりもはるかに冗長です(そして、より多くのファイルをリストします)。たとえば、それをその回答用に書いたスクリプトと比較し、同じデータで実行すると、
新しいファイルをdiff
適切に説明するには、オプションも必要です(提案された回答には表示されません)。ただし、これはに比べてはるかに遅い(桁違い)ので、後者の出力を改善する方法があります。-N
rsync
参考文献
私はずっとsha1sum(またはmd5sumでさえ、このコンテキストでは非常に安全です)に常にこだわりました。
find . -type f -print0 | xargs -0 md5sum | sort -k2 > /tmp/before
# don't miss the "sort" in there; it's important
# (later)
find . -type f -print0 | xargs -0 md5sum | sort -k2 > /tmp/after
vimdiff /tmp/before /tmp/after
# or whatever diff tool you like, even "diff -u"
名前を変更したり移動したりするファイルが多すぎる場合のように、最初のフィールドでソートしてからdiffを実行すると役立つ場合がありますが、ほとんどの場合これで十分です。
他の方法のいくつかと比較して、これには「以前の」ファイルのコピーを保持する必要がないという利点があることに注意してください。md5sum出力ファイルのみ。