diff -r nur für bestimmte Dateitypen

12

Gibt es eine Möglichkeit, einen rekursiven Unterschied zwischen zwei Verzeichnissen durchzuführen, aber nur Dateien (an ihren jeweiligen Stellen) zu vergleichen, die einem bestimmten Dateinamen oder Dateityp-Prädikat entsprechen?

Zum Beispiel möchte ich tun etwas wie

diff -r dir-a dir-b -filenames *.java, ivy.xml, build.xml

... oder noch besser:

diff -r dir-a dir-b -filetype text

Natürlich ist die Verwendung nicht obligatorisch, diffda ich eine Beschwörung mit nehme findund -exec diffmöglicherweise auch den Trick mache (ich weiß nur nicht, wie ich im letzteren Fall die komplementären Dateipfade generieren soll).

Marcus Junius Brutus
quelle
3
Es gibt eine Option zum Ausschließen von Dateien, die einem Muster entsprechen. Ich sehe keine Option, um nur Dateien einzuschließen, die dem Muster entsprechen.
Barmar
1
Alle Optionen zum Vergleichen von Verzeichnissen finden Sie unter gnu.org/software/diffutils/manual/html_node/…
Barmar
1
siehe diesen Link und siehe die Antwort von Sérgio.
Yehudahs
1
stackoverflow.com/q/10131908/2707864
sancho.s ReinstateMonicaCellio

Antworten:

1

Shell-Skript differ-r

Dieses Shellscript kann einen rekursiven Unterschied zwischen zwei Verzeichnissen ausführen, jedoch nur Dateien (an ihren jeweiligen Stellen) vergleichen, die einem bestimmten Dateinamen oder Dateitypmuster entsprechen.

#!/bin/bash

greenvid="\0033[32m"
resetvid="\0033[0m"

if [ $# -ne 3 ]
then
 echo "Usage: compare files in two directories including subdirectories"
 echo "         $0 <source-dir> <target-dir> <pattern>"
 echo "Example: $0  subdir-1     subdir-2     \"*.txt\""
 exit
fi

cmd='for pathname do
        greenvid="\0033[32m"
        resetvid="\0033[0m"
        echo -e "${greenvid}diff \"$pathname\" \"${pathname/'\"$1\"'/'\"$2\"'}\"${resetvid}"
        diff "$pathname" "${pathname/'\"$1\"'/'\"$2\"'}"
    done'
#echo "$cmd"

find "$1" -type f -name "$3" -exec bash -c "$cmd" bash {} +

Demo

Dateien:

$ find -type f
./1/ett.txt
./1/two.doc
./1/t r e.txt
./1/sub/only-one.doc
./1/sub/hello.doc
./1/sub/hejsan.doc
./differ-r2
./differ-r1
./differ-r
./2/ett.txt
./2/two.doc
./2/t r e.txt
./2/sub/hello.doc
./2/sub/hejsan.doc

Verwendungszweck:

$ ./differ-r
Usage: compare files in two directories including subdirectories
         ./differ-r <source-dir> <target-dir> <pattern>
Example: ./differ-r  subdir-1     subdir-2     "*.txt"

Laufen differ-r:

Die ausgeführten diffBefehlszeilen werden mit grünem Text gedruckt, und die Ausgabe, wenn keine Übereinstimmung vorliegt, wird mit Standardtext gedruckt (weiß auf schwarz im folgenden Screenshot).

Geben Sie hier die Bildbeschreibung ein

$ ./differ-r 1 2 "*.doc"
diff "1/two.doc" "2/two.doc"
diff "1/sub/only-one.doc" "2/sub/only-one.doc"
diff: 2/sub/only-one.doc: No such file or directory
diff "1/sub/hello.doc" "2/sub/hello.doc"
2d1
< world
diff "1/sub/hejsan.doc" "2/sub/hejsan.doc"

$ ./differ-r 1 2 "*.txt"
diff "1/ett.txt" "2/ett.txt"
2c2
< stabben
---
> farsan
diff "1/t r e.txt" "2/t r e.txt"
1c1
< t r e
---
> 3
$ 

$ ./differ-r 1 2 "*"
diff "1/ett.txt" "2/ett.txt"
2c2
< stabben
---
> farsan
diff "1/two.doc" "2/two.doc"
diff "1/t r e.txt" "2/t r e.txt"
1c1
< t r e
---
> 3
diff "1/sub/only-one.doc" "2/sub/only-one.doc"
diff: 2/sub/only-one.doc: No such file or directory
diff "1/sub/hello.doc" "2/sub/hello.doc"
2d1
< world
diff "1/sub/hejsan.doc" "2/sub/hejsan.doc"

$ ./differ-r 2 1 "*"
diff "2/ett.txt" "1/ett.txt"
2c2
< farsan
---
> stabben
diff "2/two.doc" "1/two.doc"
diff "2/t r e.txt" "1/t r e.txt"
1c1
< 3
---
> t r e
diff "2/sub/hello.doc" "1/sub/hello.doc"
1a2
> world
diff "2/sub/hejsan.doc" "1/sub/hejsan.doc"

rsync mit Filter

Wenn Sie keine Ausgabe erhalten müssen, die den Unterschied beschreibt, nur wissen, welche Dateien unterschiedlich sind oder fehlen (damit rsyncSie sie kopieren möchten), können Sie die folgende Befehlszeile verwenden.

rsync --filter="+ <pattern>" --filter="+ */" --filter="- *"--filter="- */"  -avcn <source directory>/ <target directory>

Demo

$ rsync --filter="+ *.doc" --filter="+ */" --filter="- *"  -avcn 1/ 2
sending incremental file list
./
sub/
sub/hello.doc
sub/only-one.doc

sent 276 bytes  received 35 bytes  622.00 bytes/sec
total size is 40  speedup is 0.13 (DRY RUN)

sent 360 bytes  received 41 bytes  802.00 bytes/sec
total size is 61  speedup is 0.15 (DRY RUN)
olle@bionic64 /media/multimed-2/test/test0/temp $ rsync --filter="+ *.txt" --filter="+ */" --filter="- *" -avcn 1/ 2
sending incremental file list
./
ett.txt
t r e.txt
sub/

sent 184 bytes  received 29 bytes  426.00 bytes/sec
total size is 21  speedup is 0.10 (DRY RUN)

Wenn Sie eine saubere Ausgabe ohne Kommentarzeilen und ohne Verzeichnisse wünschen, können Sie grepdie Ausgabe wie folgt ausführen:

$ pattern="*.doc"; rsync --filter="+ $pattern" --filter="+ */" --filter="- *"  -avcn 1/ 2 | grep "${pattern/\*/.\*}"
sub/hello.doc
sub/only-one.doc

Shell-Skript rsync-diff

Dieser Einzeiler kann zum Kernbefehl eines Shellskripts gemacht werden rsync-diff.

#!/bin/bash

LANG=C

if [ $# -ne 3 ]
then
 echo "Usage: compare files in two directories including subdirectories"
 echo "         $0 <source-dir> <target-dir> <pattern>"
 echo "Example: $0  subdir-1     subdir-2     \"*.txt\""
 exit
fi

pattern="$3"; rsync --filter="+ $pattern" --filter="+ */" --filter="- *" \
 -avcn "$1"/ "$2" | grep "${pattern//\*/.\*}" | grep -v \
  -e '/$' \
  -e '^sending incremental file list$' \
  -e '^sent.*received.*sec$' \
  -e '^total size is.*speedup.*(DRY RUN)$'
Sudodus
quelle
0

Da Sie erwähnt haben "Es ist eindeutig nicht obligatorisch, diff zu verwenden",

Dies sollte die Arbeit für Sie tun meld leicht konfigurierbar für welche Art von Dateitypen zu ignorieren:

Geben Sie hier die Bildbeschreibung ein

Eine weitere Alternative wäre, ein einfaches Skript zu schreiben, das von einer weißen Liste auf eine schwarze Liste übertragen wird. Anschließend wird die schwarze Liste mit der --excludeOption an den Diff übergeben .

JammingThebBits
quelle
aktualisierte Tags, um 'Kommandozeile' hinzuzufügen
Marcus Junius Brutus
0

Bei der Shell-unterstützenden Befehlsersetzung können Sie den folgenden Einzeiler verwenden (wie bereits von @JammingThebBits angegeben):

diff -r dir-a dir-b --exclude-from=<( \
find dir-a dir-b -type f -not \( -name '*.xml'  -or -name '*.java' \) \
| sed 's:^.*/\([^/]*\)$:\1:' \
)

Das funktioniert folgendermaßen: findSuchen Sie nach nicht interessierenden Dateien, sedextrahieren Sie den Basisnamen (die Ausführung basenameist extrem langsam, wenn Sie viele Dateien haben) und fügen Sie sie in eine temporäre Datei ein. Diese Datei wird dann an die diffAnweisung übergeben, sie vom Vergleich auszuschließen (doppelter Ausschluss = Einschluss).

Wenn Sie keine Befehlsersetzung haben, fügen Sie die sedAusgabe in eine Datei ein und übergeben Sie sie explizit an diff.

In dem Beispiel, in dem ich nur nach XML- und JAVA-Dateien gesucht habe, ändern Sie sie nach Bedarf, indem Sie sie durch ODER trennen.

Corrado
quelle