diff -r solo para ciertos tipos de archivos

12

¿Hay alguna manera de que pueda realizar una diferencia recursiva de dos directorios pero solo comparar (en sus respectivos lugares) archivos que coincidan con un nombre de archivo o predicado de tipo de archivo específico?

Por ejemplo, me gustaría hacer algo como

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

... o mejor:

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

Claramente, no es obligatorio usarlo, diffya que supongo que es un encantamiento findy -exec difftambién podría hacer el truco (simplemente no sé cómo generar las rutas de archivo complementarias en el último caso).

Marcus Junius Brutus
fuente
3
Hay una opción para excluir archivos que coinciden con un patrón, no veo una opción para incluir solo archivos que coinciden con el patrón.
Barmar
1
Todas las opciones específicas para comparar directorios se pueden encontrar en gnu.org/software/diffutils/manual/html_node/…
Barmar
1
vea este enlace y vea la respuesta de Sérgio.
yehudahs
1
stackoverflow.com/q/10131908/2707864
sancho.s ReinstateMonicaCellio

Respuestas:

1

Shellscript differ-r

Este shellscript puede realizar una diferencia recursiva de dos directorios, pero solo compara (en sus respectivos lugares) archivos que coinciden con un patrón de nombre de archivo o tipo de archivo específico.

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

Manifestación

Archivos:

$ 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

Uso:

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

Corriendo differ-r:

Las difflíneas de comando realizadas se imprimen con texto verde y la salida, cuando no hay coincidencia, se imprime con texto predeterminado (blanco sobre negro en la siguiente captura de pantalla).

ingrese la descripción de la imagen aquí

$ ./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 con filtro

Si no necesita obtener ningún resultado que describa la diferencia, solo sepa qué archivos son diferentes o que faltan (por lo que rsyncle gustaría copiarlos), puede usar la siguiente línea de comando.

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

Manifestación

$ 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 desea una salida limpia sin líneas de comentarios y sin directorios, puede hacer grepla salida de esta manera,

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

Shellscript rsync-diff

Esta línea única puede convertirse en el comando central de un shellscript 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
fuente
0

Como mencionó "Claramente, no es obligatorio usar diff",

Esto debería hacer el trabajo para que funden fácilmente configurable para qué tipo de tipos de archivos de ignorar:

ingrese la descripción de la imagen aquí

además, otra alternativa sería escribir un script simple que se transfiera de una lista blanca a una lista negra y luego la lista negra se pasará al diff con la --excludeopción.

JammingThebBits
fuente
etiquetas actualizadas para agregar 'línea de comandos'
Marcus Junius Brutus
0

Con la sustitución de comandos de soporte de shell , puede usar el siguiente one-liner (como ya señaló @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:' \
)

Funciona así: findbusque los archivos que no le interesan, sedextraiga el nombre base (la ejecución basenamees extremadamente lenta si tiene muchos archivos) y los coloca en un archivo temporal ; dicho archivo se pasa a diffdecirle que los excluya de la comparación (doble exclusión = inclusión).

Si no tiene sustitución de comando, coloque la sedsalida en un archivo y páselo explícitamente diff.

En el ejemplo, busqué solo archivos XML y JAVA, cambiélos según sea necesario separándolos con OR.

Corrado
fuente