Confronto tra i contenuti di due directory

73

Ho due directory che dovrebbero contenere gli stessi file e avere la stessa struttura di directory.

Penso che manchi qualcosa in una di queste directory.

Usando la shell bash, c'è un modo per confrontare le mie directory e vedere se a una di esse mancano i file che sono presenti nell'altra?

    
posta AndreaNobili 16.02.2014 - 17:54

9 risposte

49

Un buon modo per fare questo confronto è usare find con md5sum , poi un diff .

Esempio

Usa find per elencare tutti i file nella directory, quindi calcola l'hash md5 per ogni file e esegui il pipe ordinandolo per nome file in un file:

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

Fai la stessa procedura per un'altra directory:

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

Quindi confronta i risultati con due file con diff :

diff -u dir1.txt dir2.txt

O come singolo comando usando la sostituzione del processo:

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

Questa strategia è molto utile quando le due directory da confrontare non sono nella stessa macchina e devi assicurarti che i file siano uguali in entrambe le directory.

Un altro buon modo per fare il lavoro è usare il comando diff di Git (potrebbe causare problemi quando i file hanno permessi diversi - & gt; ogni file è elencato in output allora):

git diff --no-index dir1/ dir2/
    
risposta data Adail Junior 09.01.2017 - 21:05
63

Puoi usare il comando diff proprio come lo useresti per i file:

diff <directory1> <directory2>

Se vuoi vedere anche le sottocartelle e i file, puoi usare l'opzione -r :

diff -r <directory1> <directory2>
    
risposta data Alex R. 16.02.2014 - 17:59
16

Attraverso non stai usando bash, puoi farlo usando diff con --brief e --recursive :

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

Il man diff include entrambe le opzioni:

% Bl0ck_qu0te%     
risposta data Braiam 16.02.2014 - 22:19
13

Ecco un'alternativa, per confrontare solo i nomi dei file, e non i loro contenuti:

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

Questo è un modo semplice per elencare i file mancanti, ma naturalmente non rileverà file con lo stesso nome ma contenuti diversi!

(Personalmente uso il mio script diffdirs , ma fa parte di una biblioteca più grande .)

    
risposta data joeytwiddle 16.02.2014 - 18:35
3

Se vuoi rendere ogni file espandibile e pieghevole, puoi reindirizzare l'output di diff -r a Vim.

Per prima cosa diamo a Vim una regola di piegatura:

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

Ora solo:

diff -r dir1 dir2 | vim -

Puoi colpire zo e zc per aprire e chiudere le pieghe. Per uscire da Vim, premi :q<Enter>

    
risposta data joeytwiddle 06.03.2016 - 05:25
3

Ispirato dalla risposta di Sergiy, ho scritto il mio script Python per confrontare due directory.

A differenza di molte altre soluzioni, non confronta il contenuto dei file. Inoltre non entra nelle sottodirectory che mancano in una delle directory. Quindi l'output è abbastanza conciso e lo script funziona velocemente con grandi directory.

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

Se lo salvi in un file chiamato compare_dirs.py , puoi eseguirlo con Python3.x:

python3 compare_dirs.py dir1 dir2

Output di esempio:

[email protected]:~$ 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

P.S. Se devi confrontare le dimensioni dei file e gli hash dei file per le potenziali modifiche, ho pubblicato uno script aggiornato qui: link

    
risposta data Andriy Makukha 16.01.2018 - 11:01
3

Compito abbastanza facile da ottenere 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

Sostituisci i valori attuali per DIR1 e DIR2 .

Ecco l'esempio di esecuzione:

$ 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

Per migliorare la leggibilità, ecco uno script effettivo invece di 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")
    
risposta data Sergiy Kolodyazhnyy 14.11.2016 - 07:12
2

Forse un'opzione è quella di eseguire rsync due volte

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

Con la riga precedente, otterrai file in dir1 e diversi (o mancanti) in dir2. Anche cartelle con data diversa.

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

Lo stesso per 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

Puoi cancellare l'opzione -n per subire le modifiche. Copiando l'elenco dei file nella seconda cartella.

Nel caso lo facciate, forse una buona opzione è usare -u, per evitare di sovrascrivere i file più recenti.

-u, --update                skip files that are newer on the receiver
    
risposta data Ferroao 17.12.2017 - 00:26
0

Aggiungerò a questa lista un'alternativa NodeJs che ho scritto qualche tempo fa.

dir-compare

npm install dir-compare -g
dircompare dir1 dir2
    
risposta data gliviu 20.02.2018 - 21:51

Leggi altre domande sui tag