Bir dizinde varolan ancak diğer dizinde bulunmayan dosyaları bulma [kapalı]


295

Bir dizinde var ama diğerinde mevcut dosyaları bulmaya çalışıyorum, bu komutu kullanmaya çalıştım:

diff -q dir1 dir2

O iki dosyayı da bulduğu yukarıdaki komutla sorunun dir1ancak içinde dir2hem dosyaları olarak içinde dir2değil de dir1,

Dosyaları bulmaya çalışıyorum dir1ama dir2sadece içinde değil .

Verilerimin neye benzediğine ilişkin küçük bir örnek

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

Aklımda başka soru I dosyaları bulabilirsiniz nasıl dir1ama içinde dir2veya dir3tek bir komuta?

Yanıtlar:


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

Açıklama:

  • diff -r dir1 dir2 hangi dosyaların yalnızca dir1'de ve sadece dir2'de olduğunu ve varsa her iki dizinde de bulunan dosyaların değişikliklerini gösterir.

  • diff -r dir1 dir2 | grep dir1 hangi dosyaların yalnızca dir1'de olduğunu gösterir

  • awk yalnızca dosya adını yazdırmak için.


5
Ben ediyorum grepgibi sth ^dir1yaptığınızdan emin bir alamadım dir1sonra yolun görünen.
Alfe

@Alfe Geliştirilebilir. $4Örnek olarak kullanıyorum . Gerçekte, benim gerçek Ubuntu, diffİtalyanca cevaplar. $4italyanca ve ingilizce cevaplar için sorun yok, ama diğer dillerden emin değilim ...
asclepix

139

Bu işi yapmalıdır:

diff -rq dir1 dir2

Açıklanan seçenekler (fark (1) kılavuz sayfası aracılığıyla ):

  • -r - Bulunan alt dizinleri yinelemeli olarak karşılaştırın.
  • -q - Yalnızca dosyalar farklı olsa da çıktı alın.

8
Güzel! Ama bence şöyle genişletilmelidir:diff -rq dir1 dir2 | grep 'Only in dir1/'
sobi3ch

2
Bu, içeriğe göre karşılaştırmadır, ancak yavaş sürücülerde uzun sürebilir.
Smeterlink

5
Sadece -qseçenek hakkında bir not : Man sayfaları yalnızca farklı olup olmadıklarını nasıl kontrol edeceğini değil, yalnızca "Dosyaların farklı olup olmadığı çıktısını verir" der. Kaynak kodunu inceledim ve gerçek içeriği değil, sadece farklılıkları belirlemek için dosya boyutlarını kontrol ettiğini keşfettim.
ryancdotnet

İlgili -qben sadece dosya boyutunu kontrol ettiğinden yeniden olamaz seçeneği. Aynı dosya boyutu fakat farklı içeriğe sahip iki dosya karşılaştıran GNU diffutils 3.7 kullanma diff -q file1 file2çıkışlar Files file1 and file2 differ.
Stefan Schmidt

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

Bu komut size dir2'de değil dir1'de olan dosyaları verecektir .

Hakkında <( )işareti, sen 'süreç ikamesi' olarak google olabilir.


alt dizinlerle de çalışmak iyi olurdu, sanırım (ls -R dir1|sort)hile yapabilir
ulkas

1
Bu, OS X kurtarma modunda çalışır.
Anthony Vanover

@ulkas, kullanırsanız çıkış yanlış olabilir (ls -R dir|sort).
Andriy Makukha

3
vimdiff renk vurgusu ile çok daha güzel bir görsel karşılaştırma sağlar:vimdiff <(ls dir1 |sort) <(ls dir2|sort)
Logan Reed

32

Bu karşılaştırmayı yapmak için iyi bir yol kullanmaktır findile md5sumdaha sonra, diff.

Misal:

findDizindeki tüm dosyaları listelemek için kullanın , ardından her dosya için md5 karmasını hesaplayın ve bir dosyaya ekleyin:

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

Aynı işlemi başka bir dizine yapın:

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

Sonra iki dosyayı "diff" ile karşılaştırın:

diff dir1.txt dir2.txt

Bu strateji, karşılaştırılacak iki dizin aynı makinede olmadığında ve dosyaların her iki dizinde de eşit olduğundan emin olmanız gerektiğinde çok kullanışlıdır.

İşi yapmanın bir başka iyi yolu git kullanmaktır

git diff --no-index dir1/ dir2/

Saygılarımla!


1
Git git git repo içinde olmayan keyfi dizinleri bir fark yapabilir gitmedi ... harika !!! Bu cevap benim için büyük bir sorunu çözdü, teşekkürler
ViktorNova

17

Meld ( http://meldmerge.org/ ) dizinleri ve içindeki dosyaları karşılaştırmak için harika bir iş .

Meld karşılaştırma dizinleri


Dışında satır sonları söz konusu olduğunda kötü bir iş yok ...
0xC0000022L

1
Satır sonlarıyla ilgili bir sorun yaşamadım. Detay verebilir misiniz?
Catalin Hritcu

Evet, değil belirtmek satır sonları. Bu, (tekrar tekrar) geliştiricileri bu aracı kullanarak, örneğin bir CRLF'yi CRLFLF'ye dönüştürerek satır sonlarını "sabitleyen" değişiklikler yapan değişiklikler yapmalarına yol açtı.
0xC0000022L

3
Ayrıca dosya içeriğini okumakta ısrar eder ve bu nedenle >> 1GB dizinlerinde neredeyse işe yaramaz.
Tomislav Nakic-Alfirevic

13

Vim DirDiff eklentisi dizinleri karşılaştırmak için başka çok yararlı bir araçtır.

vim -c "DirDiff dir1 dir2"

Yalnızca dizinler arasında hangi dosyaların farklı olduğunu listelemekle kalmaz, aynı zamanda farklı dosyaları vimdiff ile incelemenizi / değiştirmenizi sağlar.


11

Tüm yanıtlardan memnun kalmadık, çoğu çok yavaş çalıştığı ve büyük dizinler için gereksiz yere uzun çıktı ürettiği için, iki klasörü karşılaştırmak için kendi Python betiğimi yazdım.

Diğer birçok çözümün aksine, dosyaların içeriğini karşılaştırmaz. Ayrıca başka bir dizinde eksik olan alt dizinlerin içine girmez. Böylece çıktı oldukça kısa ve senaryo hızlı çalışıyor.

#!/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])

Örnek kullanım:

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

Veya yalnızca ilk dizindeki dosyaları görmek istiyorsanız:

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 Potansiyel değişiklikler için dosya boyutlarını ve dosya karmaları karşılaştırmanız gerekiyorsa, burada güncellenmiş bir komut dosyası yayınladım: https://gist.github.com/amakukha/f489cbde2afd32817f8e866cf4abe779


Tam olarak istediğimi yapan yeterince basit komut dosyası: Toplu bir kopyayı doğrulayın: benden +1. (python2'ye dönüştürmeye ne gerek var) İpucu: setlerin kullanımı fark kısmını basitleştirebilir.
Jason Morgan

6

Başka bir (büyük dizinler için belki daha hızlı) yaklaşım:

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

sedKomut ilk dizin bileşeni kaldırır Erik`s mesaja sayesinde )


1
Bu yöntemin daha basit olduğuna inanıyorum (bu findnedenle hala bir yorum değil, ayrı bir cevap kullanıyorum): cd dir2; find . -exec [ -e ../dir1/{} ] \; -o -print 2>/dev/null Bu, dir2'de bulunan ancak dir1'de bulunmayan dosyaları yazdıracaktır.
Alexander Amelkin

5

Bu biraz geç ama birisine yardım edebilir. Diff veya rsync dosya adlarını yalnızca bu şekilde çıplak bir biçimde tükürüp tükürmediğinden emin değilim. Aşağıda genişlediğim güzel çözümü verdiği için plhn'a teşekkürler.

Yalnızca dosya adlarını istiyorsanız, yalnızca ihtiyacınız olan dosyaları temiz bir biçimde kopyalamak kolaydır, find komutunu kullanabilirsiniz.

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

Bu, hem dir1 hem de dir2'nin aynı üst klasörde olduğunu varsayar. sed, elmaları elma ile karşılaştırabilmeniz için üst klasörü kaldırır. Son sed dir1 adını geri koyar.

Sadece dosya istiyorsanız:

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

Benzer şekilde dizinler için:

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

1
Bir yapabileceğini Not cdönce findkullanım çağırmak yerine, sedörneğin: comm -23 <(cd dir1 || exit; find -type f | sort) <(cd dir2 || exit; find -type f | sort). ( exitS burada findgeçerli dizini kullanmak önlemek için cdbaşarısız olmalıdır .)
phk

Ayrıca, belirli özel karakterlere sahip dosyalar bulunduğunda çözümünüzün başarısız olabileceğini comm, desteklerin çok yeni bir sürümüne sahipseniz-z ( git.savannah.gnu.org/cgit/coreutils.git/commit/… ile birlikte gelirseniz ) yapabilirsiniz. comm -23 -z <(cd dir1 && find -type f -print0 | sort -z) <(cd dir2 && find -type f -print0 | sort -z). (Bu arada exits'nin değiştirilebileceğini de anladım .)
phk

5

Kabul edilen cevap, her iki dizinde de bulunan ancak farklı içeriğe sahip dosyaları listeler. SADECE dir1'de bulunan dosyaları listelemek için şunları kullanabilirsiniz:

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

Açıklama:

  • diff -r dir1 dir2: karşılaştır
  • grep 'Only in': 'Only in' içeren satırları al
  • grep dir1: dir içeren satırları al

5

Bu yanıt, -Dseçeneği ekleyerek @ Adail-Junior'ın önerilerinden birini optimize eder ; bu, karşılaştırılan dizinlerin hiçbiri git depoları olmadığında yardımcı olur:

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

Kullanırsanız -D, aşağıdakilerle karşılaştırmalar görmezsiniz /dev/null: text Binary files a/whatever and /dev/null differ


İki dizini karşılaştırmada çok yararlı oldu, dosyalar arasındaki farkları anında görüyorsunuz. Tabii en iyi metin içeriği olan dosyalar üzerinde çalışıyor.
Erich Kuester

1

DIFF komutunu kullanarak 2 dizini karşılaştırmanın basitleştirilmiş bir yolu

diff dosyaadı.1 dosyaadı.2> dosyaadı.dat >> Enter

çalıştırma tamamlandıktan sonra dosyaadı.dat dosyasını aç

ve şunu görürsünüz: Yalnızca dosyaadı.1: dosyaadı.2 Sadece şurada: dizin_adı: ad_of_dosya1 Yalnızca şurada: dizin_Adı: ad_of_dosya2


Neden bir .dat dosyasına çıktı almalısınız?
Vishnu NK

1

Bu, iki dizini senkronize etmek için komutları yazdırmak için bash betiğidir

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 grepseçeneği ile aramayı tersine çevirebilir -v. Bu, grepeşleşmeyen satırların raporlanmasını sağlar. Böylece içindeki dosyalar dir2listesinden dosyaları kaldırabilirsiniz dir1.

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

Seçenekler tüm satırda dize araması yapmayı -F -xsöyler grep.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.