あるディレクトリには存在するが、他のディレクトリには存在しないファイルを見つける[クローズド]


295

あるディレクトリには存在するが他のディレクトリには存在しないファイルを見つけようとしているので、次のコマンドを使用しようとしました。

diff -q dir1 dir2

それは両方のファイルを見つけることが、上記のコマンドでの問題でdir1はなく、中dir2にもファイルとしてでdir2はなくでdir1

ファイルを見つけようとしていますが、ファイルだけでdir1はありませんdir2

これは私のデータがどのように見えるかの小さなサンプルです

dir1    dir2    dir3
1.txt   1.txt   1.txt
2.txt   3.txt   3.txt
5.txt   4.txt   5.txt
6.txt   7.txt   8.txt

私の心のもう一つの問題は、私は内のファイルを見つけることができる方法でdir1はありませんでdir2か、dir3単一のコマンドでは?

回答:


390
diff -r dir1 dir2 | grep dir1 | awk '{print $4}' > difference1.txt

説明:

  • diff -r dir1 dir2 は、dir1とdir2にのみ存在するファイル、および両方のディレクトリに存在するファイルの変更(ある場合)を示しています。

  • diff -r dir1 dir2 | grep dir1 dir1にのみ存在するファイルを示します

  • awk ファイル名のみを印刷します。


5
後でパスに表示されないgrepようにしたいのですが。^dir1dir1
Alfe 2013年

@Alfe改善できます。$4例として使用します。実際、私の実際のUbuntuでは、diffイタリア語で返信します。$4イタリア語と英語の返信には問題ありませんが、他のすべての言語については
わかり

139

これは仕事をするはずです:

diff -rq dir1 dir2

オプションの説明(diff(1)のマニュアルページを使用):

  • -r -見つかったサブディレクトリを再帰的に比較します。
  • -q -ファイルが異なるかどうかのみを出力します。

8
いいね!しかし、私はそれはそのように拡張されるべきだと思います:diff -rq dir1 dir2 | grep 'Only in dir1/'
sobi3ch

2
これは内容による比較ですが、低速のドライブでは時間がかかる場合があります。
Smeterlink 2016年

5
-qオプションに関するメモ:manページには、「ファイルが異なるかどうかのみを出力する」とだけ書かれ、ファイルが異なるかどうかをチェックする方法は書かれていません。ソースコードを調べたところ、実際のコンテンツではなく、ファイルサイズのみをチェックして違いを判断していることがわかりました。
ryancdotnet

-qオプションについては、ファイルサイズのみをチェックすることを再現できません。GNU Diffutils 3.7を使用して、ファイルサイズが同じで内容が異なる2つのファイルをdiff -q file1 file2出力で比較するFiles file1 and file2 differ
Stefan Schmidt

50
comm -23 <(ls dir1 |sort) <(ls dir2|sort)

このコマンドは、dir2 ではなく dir1にあるファイルを提供します。

<( )記号については、「プロセス置換」としてググることができます。


サブディレクトリを操作することも(ls -R dir1|sort)できますが、私はトリックを実行できると思います
ulkas

1
これは、OS Xリカバリモードで機能します。
Anthony Vanover 2016

@ulkas、を使用すると、出力が不正確になる可能性があります(ls -R dir|sort)
Andriy Makukha 2018年

3
vimdiffは、カラーハイライトと非常に良く、視覚的な比較を提供します:vimdiff <(ls dir1 |sort) <(ls dir2|sort)
ローガン・リード

32

この比較を行う良い方法は、を使用findしてからを使用md5sumすることdiffです。

例:

を使用findして、ディレクトリ内のすべてのファイルを一覧表示し、各ファイルのmd5ハッシュを計算して、ファイルにパイプします。

find /dir1/ -type f -exec md5sum {} \; > dir1.txt

別のディレクトリに対して同じ手順を実行します。

find /dir2/ -type f -exec md5sum {} \; > dir2.txt

次に、結果の2つのファイルを「diff」と比較します。

diff dir1.txt dir2.txt

この戦略は、比較する2つのディレクトリが同じマシンになく、両方のディレクトリでファイルが等しいことを確認する必要がある場合に非常に役立ちます。

仕事をする別の良い方法はgitを使うことです

git diff --no-index dir1/ dir2/

宜しくお願いします!


1
私は行きませんでしたgitはgitリポジトリ内にない任意のディレクトリでdiffを実行できました...素晴らしい!!! この回答は私にとって大きな問題を解決しました。ありがとう
ViktorNova

17

Meld(http://meldmerge.org/)は、ディレクトリとその中のファイルを比較するのに優れています。

ディレクトリを溶融比較


meldが行末になるとお粗末な仕事をすることを除いて...
0xC0000022L

1
行末に問題がなかった。詳細を教えてください。
Catalin Hritcu

はい、それは行末を示すものではありません。これにより、(繰り返し)このツールを使用する開発者は、たとえばCRLFをCRLFLFにすることで行末を「修正」する変更をコミットするようになりました。
0xC0000022L 2017

3
また、ファイルの内容の読み取りを要求するため、>> 1GBディレクトリではほとんど役に立ちません。
Tomislav Nakic-Alfirevic 2018

13

vimのDirDiffプラグインは、ディレクトリを比較するための非常に便利なツールです。

vim -c "DirDiff dir1 dir2"

ディレクトリ間で異なるファイルをリストするだけでなく、異なるファイルをvimdiffで検査/変更することもできます。


11

すべての応答に満足できません。ほとんどの応答が非常に遅く、大きなディレクトリに対して不必要に長い出力を生成するため、2つのフォルダーを比較するための独自のPythonスクリプトを作成しました。

他の多くのソリューションとは異なり、ファイルの内容を比較しません。また、別のディレクトリで欠落しているサブディレクトリ内には移動しません。したがって、出力は非常に簡潔で、スクリプトは高速に動作します。

#!/usr/bin/env python3

import os, sys

def compare_dirs(d1: "old directory name", d2: "new directory name"):
    def print_local(a, msg):
        print('DIR ' if a[2] else 'FILE', a[1], msg)
    # ensure validity
    for d in [d1,d2]:
        if not os.path.isdir(d):
            raise ValueError("not a directory: " + d)
    # get relative path
    l1 = [(x,os.path.join(d1,x)) for x in os.listdir(d1)]
    l2 = [(x,os.path.join(d2,x)) for x in os.listdir(d2)]
    # determine type: directory or file?
    l1 = sorted([(x,y,os.path.isdir(y)) for x,y in l1])
    l2 = sorted([(x,y,os.path.isdir(y)) for x,y in l2])
    i1 = i2 = 0
    common_dirs = []
    while i1<len(l1) and i2<len(l2):
        if l1[i1][0] == l2[i2][0]:      # same name
            if l1[i1][2] == l2[i2][2]:  # same type
                if l1[i1][2]:           # remember this folder for recursion
                    common_dirs.append((l1[i1][1], l2[i2][1]))
            else:
                print_local(l1[i1],'type changed')
            i1 += 1
            i2 += 1
        elif l1[i1][0]<l2[i2][0]:
            print_local(l1[i1],'removed')
            i1 += 1
        elif l1[i1][0]>l2[i2][0]:
            print_local(l2[i2],'added')
            i2 += 1
    while i1<len(l1):
        print_local(l1[i1],'removed')
        i1 += 1
    while i2<len(l2):
        print_local(l2[i2],'added')
        i2 += 1
    # compare subfolders recursively
    for sd1,sd2 in common_dirs:
        compare_dirs(sd1, sd2)

if __name__=="__main__":
    compare_dirs(sys.argv[1], sys.argv[2])

使用例:

user@laptop:~$ python3 compare_dirs.py dir1/ dir2/
DIR  dir1/out/flavor-domino removed
DIR  dir2/out/flavor-maxim2 added
DIR  dir1/target/vendor/flavor-domino removed
DIR  dir2/target/vendor/flavor-maxim2 added
FILE dir1/tmp/.kconfig-flavor_domino removed
FILE dir2/tmp/.kconfig-flavor_maxim2 added
DIR  dir2/tools/tools/LiveSuit_For_Linux64 added

または、最初のディレクトリのファイルのみを表示したい場合:

user@laptop:~$ python3 compare_dirs.py dir2/ dir1/ | grep dir1
DIR  dir1/out/flavor-domino added
DIR  dir1/target/vendor/flavor-domino added
FILE dir1/tmp/.kconfig-flavor_domino added

PS潜在的な変更についてファイルサイズとファイルハッシュを比較する必要がある場合は、https//gist.github.com/amakukha/f489cbde2afd32817f8e866cf4abe779で更新されたスクリプトをこちらに公開しました


私が望んでいたことを正確に実行する簡単なスクリプト:一括コピーを確認します:自分からの+1。(ただし、python2に変換する必要があります)ヒント:セットを使用すると、diff部分が単純になる可能性があります。
Jason Morgan、

6

別の(大規模なディレクトリの方が高速かもしれません)アプローチ:

$ find dir1 | sed 's,^[^/]*/,,' | sort > dir1.txt && find dir2 | sed 's,^[^/]*/,,' | sort > dir2.txt
$ diff dir1.txt dir2.txt

sedコマンドは、最初のディレクトリコンポーネントの削除Erik`sポストのおかげで


1
私はこの方法がより簡単であると信じています(まだfindコメントを使用しており、個別の回答ではありません)。 cd dir2; find . -exec [ -e ../dir1/{} ] \; -o -print 2>/dev/null これにより、dir2には存在するがdir1には存在しないファイルが出力されます。
Alexander Amelkin

5

これは少し遅れますが、誰かを助けるかもしれません。diffまたはrsyncがファイル名だけをこのようなベアフォーマットで出力するかどうかはわかりません。plhnに感謝します。これは、以下で拡張したすばらしいソリューションを提供してくれたものです。

ファイル名だけが必要で、必要なファイルをクリーンな形式でコピーするのが簡単な場合は、findコマンドを使用できます。

comm -23 <(find dir1 | sed 's/dir1/\//'| sort) <(find dir2 | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'

これは、dir1とdir2の両方が同じ親フォルダーにあると想定しています。sedは親フォルダを削除するだけなので、リンゴとリンゴを比較できます。最後のsedはdir1の名前を戻すだけです。

ファイルだけが必要な場合:

comm -23 <(find dir1 -type f | sed 's/dir1/\//'| sort) <(find dir2 -type f | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'

同様にディレクトリの場合:

comm -23 <(find dir1 -type d | sed 's/dir1/\//'| sort) <(find dir2 -type d | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'

1
たとえば、を使用する代わりに、cd前にaを実行できます。(sは、現在のディレクトリを使用できないようにするためにここにあります。)findsedcomm -23 <(cd dir1 || exit; find -type f | sort) <(cd dir2 || exit; find -type f | sort)exitfindcd
phk

また、あなたのソリューションは、あなたがの非常に最新のバージョンがある場合、特定の特殊文字を含むファイルが、存在する場合に失敗することがありますのでご注意comm担体とを-z(付属git.savannah.gnu.org/cgit/coreutils.git/commit/...あなたが行うことができます)comm -23 -z <(cd dir1 && find -type f -print0 | sort -z) <(cd dir2 && find -type f -print0 | sort -z)。(その間、私はexitsを交換できることも
わかり

5

受け入れられた回答には、両方のディレクトリに存在するが内容が異なるファイルもリストされます。dir1に存在するファイルのみを一覧表示するには、次のコマンドを使用できます。

diff -r dir1 dir2 | grep 'Only in' | grep dir1 | awk '{print $4}' > difference1.txt

説明:

  • diff -r dir1 dir2:比較
  • grep 'Only in': 'Only in'を含む行を取得する
  • grep dir1:dirを含む行を取得します

5

この回答は、-Dオプションを追加することにより、@ Adail-Juniorからの提案の1つを最適化します。これは、比較されているディレクトリのどちらもgitリポジトリではない場合に役立ちます。

git diff -D --no-index dir1/ dir2/

使用すると-D、次との比較は表示されません/dev/nulltext Binary files a/whatever and /dev/null differ


2つのディレクトリの比較に非常に役立ちました。ファイル間の違いがすぐにわかります。もちろん、テキストコンテンツのファイルに最適です。
Erich Kuester

1

DIFFコマンドを使用して2つのディレクトリを比較する簡単な方法

diff filename.1 filename.2> filename.dat >> Enter

実行が完了した後、filename.datを開きます

そして次のように表示されます:Only in filename.1:filename.2 Only in:directory_name:name_of_file1 Only in:directory_Name:name_of_file2


なぜ.datファイルに出力する必要があるのですか?
Vishnu NK

1

これは、2つのディレクトリを同期するためのコマンドを出力するbashスクリプトです

dir1=/tmp/path_to_dir1
dir2=/tmp/path_to_dir2
diff -rq $dir1 $dir2 | sed -e "s|Only in $dir2\(.*\): \(.*\)|cp -r $dir2\1/\2 $dir1\1|" |  sed -e "s|Only in $dir1\(.*\): \(.*\)|cp -r $dir1\1/\2 $dir2\1|" 

0

GNU grepはオプションで検索を逆にすることができます-v。これによりgrep、一致しない行が報告されます。これにより、のファイルdir2リストからのファイルを削除できますdir1

grep -v -F -x -f <(find dir2 -type f -printf '%P\n') <(find dir1 -type f -printf '%P\n')

オプションは、行全体で文字列検索を実行する-F -xように指示grepします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.