Diff ein Verzeichnis rekursiv und ignoriert alle Binärdateien

77

Arbeiten an einer Fedora Constantine Box. Ich suche diffrekursiv nach zwei Verzeichnissen, um nach Quelländerungen zu suchen . Aufgrund der Einrichtung des Projekts (vor meiner eigenen Beschäftigung mit diesem Projekt! Seufz ) enthalten die Verzeichnisse sowohl Quell- und Binärdateien als auch große Binärdatensätze. Während diffing schließlich in diesen Verzeichnissen funktioniert, würde es vielleicht zwanzig Sekunden dauern, wenn ich die Binärdateien ignorieren könnte.

Soweit ich weiß, hat diff keinen Modus zum Ignorieren von Binärdateien, sondern ein Ignorierargument, das reguläre Ausdrücke innerhalb einer Datei ignoriert . Ich weiß nicht, was ich dort schreiben soll, um Binärdateien zu ignorieren, unabhängig von der Erweiterung.

Ich verwende den folgenden Befehl, aber er ignoriert keine Binärdateien. Weiß jemand, wie man diesen Befehl ändert, um dies zu tun?

diff -rq dir1 dir2
Zéychin
quelle
2
Versuchen Sie es mit cmpstatt diff, ignoriert keine Binärdateien, sollte aber schneller sein
Fredrik Pihl
2
eek. Dies ist die Aushängeschilderung für die Quellcodeverwaltung. Wenn Sie es nicht verwenden, sollten Sie es sein. Wenn die Entscheidung nicht in Ihren Händen liegt, sollten Sie leidenschaftlich streiten. Ihr Problem mit einem richtigen git Setup verschwinden würde ...
fearlesstost
6
Oh glaub mir. Ich weiß. Ich mache Bachelor-Forschung und das ist nicht ganz so eingerichtet, wie es sein sollte. Glaub mir. ICH WEISS. CVS / SVN / GIT würde dies beheben. Wissen Sie, was schlimmer ist als das? Ich wurde beauftragt, an einem Fortran-Projekt mit wenig bis gar keiner Dokumentation zu arbeiten. Es gibt 8 Versionen des Projekts in diesem Verzeichnis und jede hat verschiedene Makefiles, die (fast;)) dasselbe tun. Glauben Sie mir, ich streite mit meinem Aufseher so gut ich kann.
Zéychin

Antworten:

32

Verwenden Sie möglicherweise grep -I(was äquivalent zu ist grep --binary-files=without-match) als Filter, um Binärdateien zu sortieren.

dir1='folder-1'
dir2='folder-2'
IFS=$'\n'
for file in $(grep -Ilsr -m 1 '.' "$dir1"); do
   diff -q "$file" "${file/${dir1}/${dir2}}"
done
jon
quelle
Das sieht sehr vielversprechend aus. Ich werde das überprüfen und Sie wissen lassen, wie es geht / als Antwort akzeptieren, wenn es funktioniert!
Zéychin
2
Kennt jemand den Zweck von IFS=$'\n'?
Zubin
5
Es ist eine interne Bash-Variable. Suchen Sie nach IFS unter tldp.org/LDP/abs/html/internalvariables.html für die genaue Definition und das Verhalten.
Harsh J
1
@Zubin IFS bedeutet internes Feldtrennzeichen, das zum Erstellen eines Arrays verwendet wird, indem die Zeichenfolge auf den von IFS angegebenen Wert aufgeteilt wird
Be Wake Pandey
65

Art von Betrug, aber hier ist, was ich verwendet habe:

diff -r dir1/ dir2/ | sed '/Binary\ files\ /d' >outputfile

Dies vergleicht rekursiv dir1 mit dir2, sed entfernt die Zeilen für Binärdateien (beginnt mit "Binärdateien") und leitet sie dann in die Ausgabedatei um.

Shannon VanWagner
quelle
7
@Serg Sie können Dateien mit dem -xFlag ausschließen. Versuchen Sie diff -r -x '*.xml' dir1 dir2auch man difffür weitere Informationen.
xdhmoore
1
Wenn Sie ein System mit einer anderen Sprache verwenden, ersetzen Sie es Binary\ files\ durch das entsprechende Wort in Ihrer Sprache. Es sollten die ersten ein oder zwei Wörter sein. Auf Deutsch ist esBinärdateien\
kap
1
@xdhmoore Danke für den Kommentar! Das Hinzufügen -xist auch wiederholbar, wenn Sie mehrere Muster ausschließen möchten . So etwas wie -x '*.ext1' -x '*.ext2' -x 'ext3'.
Vasan
13

Ich kam zu dieser (alten) Frage und suchte nach etwas Ähnlichem (Konfigurationsdateien auf einem älteren Produktionsserver im Vergleich zur Standardinstallation von Apache). Das Befolgen des Vorschlags von @ anxlesstost in den Kommentaren gitist ausreichend leicht und schnell, so dass es wahrscheinlich einfacher ist als jeder der oben genannten Vorschläge. Kopieren Sie Version 1 in ein neues Verzeichnis. Dann mach:

git init
git add .
git commit -m 'Version 1'

Löschen Sie nun alle Dateien aus Version 1 in diesem Verzeichnis und kopieren Sie Version 2 in das Verzeichnis. Mach jetzt:

git add .
git commit -m 'Version 2'
git show

Dies zeigt Ihnen Gits Version aller Unterschiede zwischen dem ersten Commit und dem zweiten. Bei Binärdateien wird lediglich angegeben, dass sie sich unterscheiden. Alternativ können Sie für jede Version einen Zweig erstellen und versuchen, diese mit den Zusammenführungswerkzeugen von git zusammenzuführen.

RekursivIronic
quelle
5

Wenn die Namen der binären Dateien in Ihrem Projekt ein bestimmtes Muster folgen ( *.o, *.so, ...) , wie sie in der Regel tun, können Sie diese Muster in einer Datei speichern , und geben Sie es mit -XBindestrich (X).

Inhalt meiner exclude_file

*.o
*.so
*.git

Befehl:

diff -X exclude_file -r . other_tree > my_diff_file

AKTUALISIEREN:

-xkann stattdessen verwendet werden -X, um Ausschlussmuster in der Befehlszeile und nicht in einer Datei anzugeben:

diff -r -x *.o -x *.so -x *.git dir1 dir2
Mohan S Nayaka
quelle
1
Es ist -x NICHT -X.
Code_dweller
2
@code_dweller Beide existieren: -xdient zum Ausschließen eines Musters in der Befehlszeile, während -Xdie Datei angibt, die alle auszuschließenden Muster enthält.
Simlev
0

Verwenden Sie eine Kombination aus findund den fileBefehl. Dies erfordert, dass Sie einige Nachforschungen über die Ausgabe des fileBefehls in Ihrem Verzeichnis anstellen. Im Folgenden gehe ich davon aus, dass die Dateien, die Sie unterscheiden möchten, als ASCII gemeldet werden. ODER verwenden Sie grep -vdiese Option, um die Binärdateien herauszufiltern.

#!/bin/bash

dir1=/path/to/first/folder
dir2=/path/to/second/folder

cd $dir1
files=$(find . -type f -print | xargs file | grep ASCII | cut -d: -f1)

for i in $files;
do
    echo diffing $i ---- $dir2/$i
    diff -q $i $dir2/$i
done

Da Sie wahrscheinlich die Namen der riesigen Binärdateien kennen, platzieren Sie sie in einem Hash-Array und führen Sie den Diff nur aus, wenn sich eine Datei nicht im Hash befindet.

#!/bin/bash

dir1=/path/to/first/directory
dir2=/path/to/second/directory

content_dir1=$(mktemp)
content_dir2=$(mktemp)

$(cd $dir1 && find . -type f -print > $content_dir1)
$(cd $dir2 && find . -type f -print > $content_dir2)

echo Files that only exist in one of the paths
echo -----------------------------------------
diff $content_dir1 $content_dir2    

#Files 2 Ignore
declare -A F2I
F2I=( [sqlite3]=1 [binfile2]=1 )

while read f;
do
    b=$(basename $f)
    if ! [[ ${F2I[$b]} ]]; then
        diff $dir1/$f $dir2/$f
    fi
done < $content_dir1
Fredrik Pihl
quelle
0

Nun, als grobe Art der Prüfung könnten Sie Dateien ignorieren, die mit / \ 0 / übereinstimmen.

Troy
quelle
1
Das Problem ist, dass es nicht so aussieht, als würde diff das Ignorieren von Dateien überhaupt unterstützen.
Zéychin
2
Das -xFlag kann verwendet werden, um Dateien zu ignorieren.
xdhmoore