diff -r uniquement pour certains types de fichiers

12

Existe-t-il un moyen de réaliser un diff récursif de deux répertoires mais de comparer uniquement (à leurs emplacements respectifs) les fichiers qui correspondent à un nom de fichier ou un prédicat de type de fichier spécifique?

Par exemple, je voudrais faire quelque chose comme

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

... ou mieux encore:

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

De toute évidence, il n'est pas obligatoire d'utiliser diffcar je suppose une incantation avec findet -exec diffpourrait également faire l'affaire (je ne sais tout simplement pas comment générer les chemins de fichiers complémentaires dans ce dernier cas).

Marcus Junius Brutus
la source
3
Il y a une option pour exclure les fichiers qui correspondent à un modèle, je ne vois pas d'option pour inclure uniquement les fichiers qui correspondent au modèle.
Barmar
1
Toutes les options spécifiques à la comparaison des répertoires peuvent être trouvées sur gnu.org/software/diffutils/manual/html_node/…
Barmar
1
voir ce lien et voir la réponse de Sérgio.
yehudahs
1
stackoverflow.com/q/10131908/2707864
sancho.s ReinstateMonicaCellio

Réponses:

1

Shellscript differ-r

Ce shellscript peut effectuer un diff récursif de deux répertoires mais comparer uniquement (à leurs emplacements respectifs) les fichiers qui correspondent à un nom de fichier ou un modèle de type de fichier spécifique.

#!/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 {} +

Démo

Des dossiers:

$ 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

Usage:

$ ./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"

Courir differ-r:

Les difflignes de commande exécutées sont imprimées avec du texte vert et la sortie, lorsqu'il n'y a pas de correspondance, est imprimée avec le texte par défaut (blanc sur noir dans la capture d'écran suivante).

entrez la description de l'image ici

$ ./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 avec filtre

Si vous n'avez pas besoin d'obtenir de sortie décrivant la différence, sachez uniquement quels fichiers sont différents ou manquants (de sorte que vous rsyncsouhaitez les copier), vous pouvez utiliser la ligne de commande suivante.

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

Démo

$ 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)

Si vous voulez une sortie propre sans lignes de commentaires et sans répertoires, vous pouvez grepla sortie comme ça,

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

Shellscript rsync-diff

Ce one-liner peut être transformé en commande de base d'un script shell 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
la source
0

Comme vous avez mentionné "Il est clair qu'il n'est pas obligatoire d'utiliser diff",

Cela devrait faire le travail pour vous MELD facilement configurable pour ce genre de types de fichiers à ignorer:

entrez la description de l'image ici

de plus, une autre alternative serait d'écrire un script simple qui sera transféré d'une liste blanche à une liste noire et ensuite la liste noire sera transmise au diff avec l' --excludeoption.

JammingThebBits
la source
balises mises à jour pour ajouter la «ligne de commande»
Marcus Junius Brutus
0

Avec le shell prenant en charge la substitution de commandes, vous pouvez utiliser le one-liner suivant (comme déjà noté par @JammingThebBits):

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

Cela fonctionne comme ceci: findrecherchez les fichiers sans intérêt, sedextrayez le nom de base (l'exécution basenameest extrêmement lente si vous avez plusieurs fichiers) et les place dans un fichier temporaire ; ce fichier est ensuite passé à difflui dire de les exclure de la comparaison (double exclusion = inclusion).

Si vous n'avez pas de substitution de commande, placez la sedsortie dans un fichier et passez-la explicitement à diff.

Dans l'exemple, je n'ai recherché que les fichiers XML et JAVA, modifiez-les si nécessaire en les séparant par OR.

Corrado
la source