Evite que diff verifique la nueva línea al final del archivo

21

Tengo dos grandes árboles, que quiero comparar. Algunos de los archivos en el árbol difieren solo porque uno tiene una nueva línea al final y el otro archivo carece de esta nueva línea. Quiero ignorar este hecho. He intentado llamar diffasí:

diff --ignore-all-space -r <dir1> <dir2>

Y esto está funcionando. Mi problema es que también ignora otras diferencias (relacionadas con el espacio), que pueden ser importantes.

En resumen: solo quiero ignorar la nueva línea en EOF. ¿Es esto posible con diff?

dangonfast
fuente

Respuestas:

17

Básicamente, necesita comparar dos archivos, ignorando condicionalmente el byte final. No hay una opción 'diff' para hacer esto, pero hay varias formas de hacerlo (por ejemplo, hexadecimal diff también me viene a la mente).

Para usar 'diff', básicamente tiene que modificar los archivos a los que les falta la nueva línea al final de un archivo, y luego compararlos. Puede crear un directorio temporal con los archivos modificados, o con un poco de secuencia de comandos se puede hacer en la memoria. (En cuanto a cuál se prefiere depende de la preferencia, el tamaño del archivo, el número de archivos ...)

Por ejemplo, lo siguiente modificará el contenido de un archivo (se usa sed -ipara modificar en el lugar, esto solo se imprime en stdout) para agregar una nueva línea si falta una (o dejar el archivo sin cambios si ya hay una nueva línea):

sed -e '$a\'  file1.txt

Y solo para revisar la sintaxis 'diff' (devolver verdadero significa que son iguales, falso significa diferente):

$ diff a/file1.txt   b/file1.txt  \
      && echo '** are same' || echo '** are different'
2c2
< eof
---
> eof
\ No newline at end of file
** are different

Verifique que solo los espacios en blanco sean diferentes:

$ diff --ignore-all-space  a/file1.txt   b/file1.txt \
     && echo '** are same' || echo '** are different'
** are same

En bash, podemos usar 'sed' para manipular el contenido del archivo a medida que se pasa a 'diff' (los archivos originales no se modifican):

$ diff <(sed -e '$a\' a/file1.txt) <(sed -e '$a\' b/file1.txt) \
     && echo '** are same' || echo '** are different'
** are same

Ahora todo lo que tiene que hacer es emular diff -rpara comparar directorios de forma recursiva. Si compara directorios ay b, para todos los archivos en a(p. Ej. a/dir1/dir2/file.txt) , Deriva la ruta al archivo en b(p. Ej. b/dir1/dir2/file.txt) Y compara:

$ for f in $( find a -type f  )
> do
>    diff <(sed -e '$a\' $f) <(sed -e '$a\' b/${f#*/})
> done

Una versión un poco más detallada:

$ for f in $( find a -type f  )
> do
>   f1=$f
>   f2=b/${f#*/}
>   echo "compare: $f1 $f2"
>   diff <(sed -e '$a\' $f1) <(sed -e '$a\' $f2) \
>       && echo '** are same' || echo '** are different'
> done && echo '** all are same' || echo '** all are different'
compare: a/file1.txt b/file1.txt
** are same
compare: a/file2.txt b/file2.txt
** are same
** all are same
Miguel
fuente
¿podría explicar qué sed -e '$a\'hace exactamente? thx
törzsmókus
ejecutar sed, dada la siguiente -esecuencia de comandos / expresión ( ), que coincide con el final del archivo ( $), y realizar la acción "agregar" (a \), pero en realidad no especifica ningún texto (nada después del `\`) que todavía va a agregar un EOF / nueva línea al final del archivo (solo si falta).
michael
Gracias. No he visto a\ aún.
törzsmókus
1

Resolví el problema agregando una nueva línea a cada uno de los archivos e ignorando las líneas en blanco en la diferencia (opción -B). Estas soluciones pueden no ser adecuadas para su caso de uso, pero podrían ayudar a otros:

echo >> $FILE1 
echo >> $FILE2
diff -B $FILE1 FILE2 
Jakob
fuente
0

Canalice la salida de diffun grepcomando que suelte el mensaje que no desea ver.

David Schwartz
fuente
no está bien. diff -r existe con resultado! = 0 si no agrego --ignore-all-space. Para ser claros: quiero que diff ignore las nuevas líneas en EOF, y solo en EOF. Y quiero que informe un resultado que coincida con este criterio. Es decir, si los archivos en el árbol difieren solo en la nueva línea en EOF, eso no debe considerarse una diferencia y, por lo tanto, diff debe devolver 0.
dangonfast
0

Solo pensé en un enfoque diferente, que funcionará para archivos más grandes (y aún así no copia ni modifica los archivos originales). Todavía tendría que emular el recorrido recursivo del directorio (y hay varias formas de hacerlo), pero este ejemplo no usa 'sed', sino que simplemente compara dos archivos, excluyendo el último byte, usando cmp, por ejemplo,

$ cmp  a/file1.txt  b/file1.txt  && echo '** are same' || echo '** are different'
cmp: EOF on b/file1.txt
** are different

$ du -b a/file1.txt  b/file1.txt 
13  a/file1.txt
12  b/file1.txt

$ cmp  -n 12 a/file1.txt  b/file1.txt  && echo '** are same' || echo '** are different'
** are same

Todavía repita todos los archivos en el directorio, y para dos archivos a / file.txt y b / file.txt, calcule el tamaño de archivo más grande y reste uno, luego haga un diff binario ( cmp) usando este número de bytes (también en golpetazo):

(( bytes = $(du -b a/file.txt  b/file.txt  | sort -nr | head -1  | cut -f1) - 1 ))
cmp -n $bytes a/file.txt b/file.txt

Recorrer los archivos sería lo mismo que en la otra respuesta usando sedy diff.

Miguel
fuente
0

La respuesta es simple.
El mensaje sobre la nueva línea que falta no está en la secuencia de salida de, diffsino en la secuencia de error. Así que dóblalo al nirvana y listo

diff -rqEeB fileA fileB 2> /dev/null
Yunzen
fuente
diff devuelve un valor! = 0 si encuentra diferencias y quiero verificar ese valor. Redirigir a / dev / null no hace que diff se olvide de esa diferencia, por lo que el valor devuelto es! = 0, que no quiero. Quiero que diff considere dos archivos iguales si la única diferencia es la última línea nueva
dangonfast
-1

Hay una bandera en diff commnad: --strip-trailing-crque hace exactamente lo que pediste

dharman
fuente
-1. ¿Has probado esto? Se trata /r/ncomo /ny no tiene nada que ver con extra /njusto antes de EOF.
Kamil Maciorowski
He intentado esto y lo he usado para diferenciar archivos con diferentes dos / unix nueva línea ... ¿no es correcto?
Dharman
La pregunta es sobre ignorar la nueva línea en EOF (final del archivo) solamente.
Kamil Maciorowski