Vraag De inhoud van twee mappen vergelijken


Ik heb twee mappen die dezelfde bestanden moeten bevatten en dezelfde directorystructuur hebben.

Ik denk dat er iets ontbreekt in een van deze mappen.

Met behulp van de bash-shell, is er een manier om mijn mappen te vergelijken en te zien of een van de bestanden ontbreekt die in de andere aanwezig zijn?


66
2018-02-16 16:54


oorsprong


Wat is de uitvoer van bash --version? - jobin
Gelijkaardig maar specifieker: stackoverflow.com/questions/16787916/... - Ciro Santilli 新疆改造中心 六四事件 法轮功


antwoorden:


Een goede manier om deze vergelijking te maken is om te gebruiken find met md5sum, dan een diff.

Voorbeeld

Gebruik find om alle bestanden in de map op te sommen en bereken vervolgens de md5-hash voor elk bestand en leid deze gesorteerd op bestandsnaam naar een bestand:

find /dir1/ -type f -exec md5sum {} + | sort -k 2 > dir1.txt

Voer dezelfde procedure uit voor de andere map:

find /dir2/ -type f -exec md5sum {} + | sort -k 2 > dir2.txt

Vergelijk dan het resultaat twee bestanden met diff:

diff -u dir1.txt dir2.txt

Of als een enkele opdracht met behulp van procesvervanging:

diff <(find /dir1/ -type f -exec md5sum {} + | sort -k 2) <(find /dir2/ -type f -exec md5sum {} + | sort -k 2)

Deze strategie is erg handig wanneer de twee te vergelijken directory's zich niet in dezelfde machine bevinden en u ervoor moet zorgen dat de bestanden in beide mappen gelijk zijn.

Een andere goede manier om het werk te doen is met Git's diff commando (kan problemen veroorzaken wanneer bestanden verschillende rechten hebben -> elk bestand wordt dan getoond in de uitvoer):

git diff --no-index dir1/ dir2/

43
2018-01-09 20:05



Dit werkt niet zonder een extra sorteerstap, omdat de volgorde waarin find lijst zal de bestanden in het algemeen verschillen tussen de twee mappen. - Faheem Mitha
Men kan de methode gebruiken die wordt beschreven in askubuntu.com/a/662383/15729 om de bestanden te sorteren. - Faheem Mitha
Ik krijg de fout `` find: md5sum: geen bestand of map - Houman
@Houman Ik weet niet wat Linux Distro je gebruikt, maar misschien moet je een pakket installeren dat de md5sum zal leveren. In Fedora 26 kun je het installeren met: #dnf coreutils installeren - Adail Junior
@AdailJunior Ik ben op Mac Sierra. Bedankt - Houman


U kunt de diff commando net zoals je het zou gebruiken voor bestanden:

diff <directory1> <directory2>

Als u ook submappen en bestanden wilt zien, kunt u de -r keuze:

diff -r <directory1> <directory2>

58
2018-02-16 16:59



Ik wist het niet diff werkt ook voor directory's (man diff bevestigde dat), maar dit onderzoekt niet recursief op veranderingen in subdirectories in subdirectories. - jobin
@Jobin Dat is raar ... Voor mij werkt het. - Alex R.
Ik heb zoiets als dit: a/b/c/d/a, x/b/c/d/b. Zie wat diff a x geeft jou. - jobin
Je moet de gebruiken -r keuze. Dat (diff -r a x) geeft me: Only in a/b/c/d: a. only in x/b/c/d: b. - Alex R.
diff toon me het verschil INTO-bestanden, maar niet als een map een bestand bevat dat de andere niet bevat !!! Ik hoef de verschillen niet in het bestand te weten, maar ook of een bestand in een directory staat en niet in het andere - AndreaNobili


Omdat je bash niet gebruikt, kun je het doen met diff met --brief en --recursive:

$ diff -rq dir1 dir2 
Only in dir2: file2
Only in dir1: file1

De man diff omvat beide opties:

-q, --brief
                rapport alleen wanneer bestanden verschillen

-r, --recursive
                recursief vergelijken gevonden subdirectories


14
2018-02-16 21:19





Hier is een alternatief om alleen bestandsnamen te vergelijken, en niet de inhoud:

diff <(cd folder1 && find . | sort) <(cd folder2 && find . | sort)

Dit is een eenvoudige manier om ontbrekende bestanden te vermelden, maar natuurlijk zal niet detecteren bestanden met dezelfde naam maar met verschillende inhoud!

(Persoonlijk gebruik ik de mijne diffdirs script, maar dat is onderdeel van een grotere bibliotheek.)


13
2018-02-16 17:35



Gebruik best procesvervanging, geen tijdelijke bestanden ... - mniip
Goede suggestie, bedankt. - joeytwiddle
Merk op dat dit geen bestandsnamen met bepaalde speciale karakters ondersteunt, in dat geval zou je misschien nul-scheidingstekens willen gebruiken die AFAIK diff ondersteunt vanaf nu niet. Maar er is comm die het sindsdien ondersteunt git.savannah.gnu.org/cgit/coreutils.git/commit/... dus zodra het een coreutils bij jou in de buurt komt, kun je het doen comm -z <(cd folder1 && find -print0 | sort) <(cd folder2 && find -print0 | sort -z) (waarvan u de uitvoer moet converteren naar het formaat dat u nodig hebt met behulp van de --output-delimiterparameter en extra hulpmiddelen). - phk


Als u elk bestand uitbreidbaar en samenvouwbaar wilt maken, kunt u de uitvoer van pipen diff -r in Vim.

Laten we eerst Vim een ​​vouwregel geven:

mkdir -p ~/.vim/ftplugin
echo "set foldexpr=getline(v:lnum)=~'^diff.*'?'>1':1 foldmethod=expr fdc=2" >> ~/.vim/ftplugin/diff.vim

Nu gewoon:

diff -r dir1 dir2 | vim -

Je kunt slaan zo en zc om vouwen te openen en te sluiten. Om uit Vim te komen, druk op :q<Enter>


3
2018-03-06 04:25





Geïnspireerd door het antwoord van Sergiy, heb ik mijn eigen Python-script geschreven om twee mappen met elkaar te vergelijken.

In tegenstelling tot veel andere oplossingen vergelijkt het de inhoud van de bestanden niet. Het gaat ook niet naar submappen die ontbreken in een van de mappen. Dus de output is vrij beknopt en het script werkt snel met grote mappen.

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

Als u het opslaat in een bestand met de naam compare_dirs.py, je kunt het gebruiken met Python3.x:

python3 compare_dirs.py dir1 dir2

Voorbeelduitvoer:

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

Postscriptum Als u bestandsgroottes en bestandshulsen moet vergelijken voor mogelijke wijzigingen, heb ik hier een bijgewerkt script gepubliceerd: https://gist.github.com/amakukha/f489cbde2afd32817f8e866cf4abe779


3
2018-01-16 10:01



Bedankt, ik heb een optionele derde param regexp toegevoegd om over te slaan / negeren gist.github.com/mscalora/e86e2bbfd3c24a7c1784f3d692b1c684 om precies te maken wat ik nodig heb zoals: cmpdirs dir1 dir2 '/\.git/' - Mike


Tamelijk eenvoudige taak om te bereiken in python:

python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' DIR1 DIR2

Vervang actuele waarden voor DIR1 en DIR2.

Hier is voorbeeldrun:

$ python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' Desktop/ Desktop
SAME
$ python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' Desktop/ Pictures/
DIFF

Voor de leesbaarheid is dit een echt script in plaats van one-liner:

#!/usr/bin/env python
import os, sys

d1 = os.listdir(sys.argv[1])
d2 = os.listdir(sys.argv[2])
d1.sort()
d2.sort()

if d1 == d2:
    print("SAME")
else:
    print("DIFF")

2
2017-11-14 06:12



Merk op dat de os.listdir geeft geen specifieke volgorde. Dus de lijsten kunnen dezelfde dingen in verschillende volgorde hebben en de vergelijking zou mislukken. - muru
@muru goed punt, ik zal daar ook sortering aan toevoegen - Sergiy Kolodyazhnyy


Misschien is een optie om rsync twee keer uit te voeren

rsync -r -n -t -v --progress -c -s /dir1/ /dir2/

Met de vorige regel krijg je bestanden die in map 1 staan ​​en die verschillen (of ontbreken) in map2. Ook mappen met verschillende datum.

rsync -r -n -t -v --progress -c -s /dir2/ /dir1/

Hetzelfde voor dir2

#from the rsync --help :
-r, --recursive             recurse into directories
-n, --dry-run               perform a trial run with no changes made
-t, --times                 preserve modification times
-v, --verbose               increase verbosity
    --progress              show progress during transfer
-c, --checksum              skip based on checksum, not mod-time & size
-s, --protect-args          no space-splitting; only wildcard special-chars

U kunt de -n optie verwijderen om de wijzigingen te ondergaan. Dat is het kopiëren van de lijst met bestanden naar de tweede map.

In het geval dat u dat doet, is het misschien een goede optie om -u te gebruiken om te voorkomen dat u nieuwere bestanden overschrijft.

-u, --update                skip files that are newer on the receiver

2
2017-12-16 23:26